def optimizeHelical(vessel, layerNumber, puckProperties, burstPressure, minPolarOpening, dropIndicies, verbose): if verbose: log.info('Add helical layer') # get location of critical element minAngle, _, _ = optimizeAngle( vessel, minPolarOpening, layerNumber, 1., False, targetFunction=getAngleAndPolarOpeningDiffByAngle) bounds = [minAngle, 70] layerOk = False while not layerOk: angle, funcVal, loopIt = minimizeUtilization(vessel, layerNumber, bounds, dropIndicies, puckProperties, burstPressure, verbose=verbose) layerOk, bounds = checkThickness(vessel, angle, bounds) mandrel = vessel.getVesselLayer(layerNumber).getOuterMandrel1() newDesignIndex = np.argmin( np.abs(mandrel.getRArray() - vessel.getPolarOpeningR(layerNumber, True))) return angle, funcVal, loopIt, newDesignIndex
def applySettings(filename=None): """reads settings from the settingsfile""" from tankoh2 import log defaultSettingsFileName = 'settings.json' searchDirs = ['.', os.path.dirname(__file__), os.path.dirname(os.path.dirname(os.path.dirname(__file__)))] if filename is None: for searchDir in searchDirs: if defaultSettingsFileName in os.listdir(searchDir): # look for settings file in actual folder filename = os.path.join(searchDir, defaultSettingsFileName) if filename is None: writeSettingsExample() raise Tankoh2Error( f'Could not find the settings file "{defaultSettingsFileName}" in the following folders: {searchDirs}.\n' f'An example settings file is written to ./{exampleFileName}.\n' f'Please add the requried settings and rename the file to {exampleFileName.replace("_example","")}.') with open(filename, 'r') as f: settings = json.load(f) major, minor = str(sys.version_info.major), str(sys.version_info.minor) pyVersionString = major+minor # v 0.90c pythonApiPath = os.path.join(settings['mycropychainPath'], f'pythonAPI\python{pyVersionString}_x64') if not os.path.exists(pythonApiPath): # v 0.95.2 pythonApiPath = os.path.join(settings['mycropychainPath'], f'pythonAPI\python{pyVersionString}') if not os.path.exists(pythonApiPath): # v0.95.3 pyVersionString = f'{major}_{minor}' pythonApiPath = os.path.join(settings['mycropychainPath'], f'pythonAPI\{pyVersionString}') #abaqusPythonLibPath = os.path.join(settings['mycropychainPath'], 'abaqus_interface_0_89') abaqusPythonLibPath = os.path.join(settings['mycropychainPath'], 'abaqus_interface_0_95') log.info(f'Append mycropychain path to sys path: {pythonApiPath}') sys.path.append(pythonApiPath) # import API - MyCrOChain GUI with activiated TCP-Connector needed try: import mycropychain as pychain except ModuleNotFoundError: try: if minor == '6': import mycropychain36 as pychain else: # minor == '8' import mycropychain38 as pychain except ModuleNotFoundError: raise Tankoh2Error('Could not find package "mycropychain". Please check the path to mycropychain in the ' 'settings file.') else: if len(pychain.__dict__) < 10: # len(pychain.__dict__) was 8 on failure and 17 on success raise Tankoh2Error('Could not connect to mycropychain GUI. Did you start the GUI and activated "TCP Conn."?') # set general path information global myCrOSettings myCrOSettings = pychain.utility.MyCrOSettings() myCrOSettings.abaqusPythonLibPath = abaqusPythonLibPath
def writeSettingsExample(): """writes an example for settings""" from tankoh2 import log log.info(f'write file {exampleFileName}') with open('settings_example.json', 'w') as f: json.dump({'comment': "Please rename this example file to 'settings.json' and include the required settings. " "For paths, please use '\\' or '/'", 'mycropychainPath': ''}, f, indent=2)
def getPolarOpeningDiffByAngle(angle, args): vessel, layerNumber, targetPolarOpening, verbose = args if verbose: log.info(f'angle {angle}') actualPolarOpening = windLayer(vessel, layerNumber, angle, verbose) if verbose: log.info( f'angle {angle}, actualPolarOpening {actualPolarOpening}, targetPolarOpening {targetPolarOpening}' ) return abs(targetPolarOpening - actualPolarOpening)
def getAngleAndPolarOpeningDiffByAngle(angle, args): vessel, layerNumber, targetPolarOpening, verbose = args if verbose: log.info(f'angle {angle}') actualPolarOpening = windLayer(vessel, layerNumber, angle, verbose) funVal = angle + abs(targetPolarOpening - actualPolarOpening) if verbose: log.info( f'angle {angle}, target function val {funVal}, actualPolarOpening {actualPolarOpening}, targetPolarOpening {targetPolarOpening}' ) return funVal
def getMaxFibreFailureByAngle(angle, args): """Returns the maximum puck fibre failure index after setting and winding the given angle""" vessel, layerNumber, puckProperties, burstPressure, dropIndicies, verbose = args if hasattr(angle, '__iter__'): angle = angle[0] if angle is not None: actualPolarOpening = windLayer(vessel, layerNumber, angle, verbose) if actualPolarOpening is np.inf: return np.inf maxFF, maxIndex = _getMaxFibreFailure(args) if verbose: log.info(f'angle {angle}, max fibre failure {maxFF}, index {maxIndex}') return maxFF
def getMaxFibreFailureByShift(shift, args): """Returns the maximum puck fibre failure index after setting and winding the given hoop layer shift""" if hasattr(shift, '__iter__'): shift = shift[0] vessel, layerNumber, puckProperties, burstPressure, dropIndicies, verbose = args vessel.setHoopLayerShift(layerNumber, shift, True) actualPolarOpening = windLayer(vessel, layerNumber, verbose=verbose) if actualPolarOpening is np.inf: return np.inf maxFF, maxIndex = _getMaxFibreFailure(args) if verbose: log.info( f'hoop shift {shift}, max fibre failure {maxFF}, index {maxIndex}') return maxFF
def optimizeHoop(vessel, layerNumber, puckProperties, burstPressure, dropIndicies, maxHoopShift, verbose): if verbose: log.info('Add hoop layer') bounds = [0, maxHoopShift] shift, funcVal, loopIt = minimizeUtilization( vessel, layerNumber, bounds, dropIndicies, puckProperties, burstPressure, targetFunction=getMaxFibreFailureByShift, verbose=verbose) newDesignIndex = 0 return shift, funcVal, loopIt, newDesignIndex
def optimze_winding_parameters_friction(vessel, wendekreisradius): # popt, pcov = curve_fit(winding_helical_layer, layerindex, wk_goal, bounds=([0.], [1.])) popt = minimize_scalar(winding_helical_layer, tol=0.00001, method='Golden', args=[vessel, wendekreisradius], options={ "maxiter": 1000, 'disp': True }) # popt = minimize(winding_helical_layer, x0 = (1.), method = 'BFGS', args=[vessel, wendekreisradius], # options={'gtol': 1e-6, 'disp': True}) friction = popt.x log.info(popt.success) return friction, winding_helical_layer(friction, [vessel, wendekreisradius])
def getPolarOpeningDiffHelical(friction, args): vessel, wendekreisradius, layerindex, verbose = args vessel.setLayerFriction(layerindex, friction[0], True) try: vessel.runWindingSimulation(layerindex + 1) wk = vessel.getPolarOpeningR(layerindex, True) except (IOError, ValueError, IOError, ZeroDivisionError): raise log.info('I have to pass') if verbose: log.info( f"layer {layerindex}, friction {friction}, po actual {wk}, po target {wendekreisradius}, po diff {wk-wendekreisradius}" ) # log.info('this helical layer shoud end at', wendekreisradius[layerindex], 'mm but is at', wk, 'mm so there is a # deviation of', wendekreisradius[layerindex]-wk, 'mm') if abs(wendekreisradius[layerindex]-wk) < 2.: # arr_fric.append(abs(friction)) arr_wk.append(wk) return abs(wk - wendekreisradius)
def getPolarOpeningXDiffHoop(shift, args): vessel, polarOpeningX, layerindex, verbose = args vessel.setHoopLayerShift(layerindex, shift, True) try: vessel.runWindingSimulation(layerindex + 1) wk = vessel.getPolarOpeningX(layerindex, True) except (IOError, ValueError, IOError, ZeroDivisionError, RuntimeError): raise log.info('I have to pass') if verbose: log.info( f"layer {layerindex}, shift {shift}, po actual {wk}, po target {polarOpeningX}, po diff {wk - polarOpeningX}" ) # log.info('this hoop layer shoud end at', krempenradius[layerindex], 'mm but is at', wk, 'mm so there is a # deviation of', krempenradius[layerindex]-wk, 'mm') return abs(wk - polarOpeningX)
def main(): sampleFile = '' # + 'C:/PycharmProjects/tankoh2/tmp/doe_isotensoid_20201028_210108/sampleX.txt' numberOfSamples = 201 startTime = datetime.datetime.now() names = list(lb.keys()) runDir = getRunDir(f'doe_{dome}', basePath=os.path.join(programDir, 'tmp')) winder = TankWinder(lb, ub, runDir) if sampleFile: lcvt = DOEfromFile(sampleFile) else: lcvt = LatinizedCentroidalVoronoiTesselation(numberOfSamples, len(names)) sampleX = BoundsHandler.scaleToBoundsStatic(lcvt.sampleXNormalized, list(lb.values()), list(ub.values())) plotGeometryRange([lb['r'], ub['r']], [lb['lzylByR'], ub['lzylByR']], plotDir=runDir, samples=sampleX) return print(sampleX.shape) lcvt.xToFile(os.path.join(runDir, 'sampleX.txt')) lcvt.xToFileStatic(os.path.join(runDir, 'sampleX_bounds.txt'), sampleX) sampleY = getY(sampleX, winder, verbose=True, runDir=runDir) # store samples lcvt.yToFile(os.path.join(runDir, 'sampleY.txt'), winder, sampleY) # lcvt.xyToFile(os.path.join(runDir, 'full_doe2.txt'), winder, sampleY, True) allSamples = [names + winder.resultNames] for inputSample, outputSample in zip(sampleX.T, sampleY): if hasattr(outputSample, '__iter__'): allSamples.append(list(inputSample) + list(outputSample)) else: allSamples.append(list(inputSample) + list([outputSample])) with open(os.path.join(runDir, 'full_doe.txt'), 'w') as f: f.write(indent(allSamples, hasHeader=True)) duration = datetime.datetime.now() - startTime log.info(f'runtime {duration.seconds} seconds')
def main(): # ######################################################################################### # SET Parameters of vessel # ######################################################################################### servicepressure = 700. #bar saftyFactor = 1. layersToWind = 48 optimizeWindingHelical = True optimizeWindingHoop = False tankname = 'NGT-BIT-2020-09-16' dataDir = os.path.join(programDir, 'data') dzyl = 400. # mm polarOpening = 48. / 2. # mm lzylinder = 500. # mm dpoints = 4 # data points for liner contour defaultLayerthickness = 0.125 hoopLayerThickness = 0.125 helixLayerThickenss = 0.129 rovingWidth = 3.175 numberOfRovings = 10 #1 bandWidth = rovingWidth * numberOfRovings log.info( f'winding using {numberOfRovings} robings with {rovingWidth}mm resulting in bandwith of {bandWidth}' ) tex = 446 # g / km rho = 1.78 # g / cm^3 sectionAreaFibre = tex / (1000. * rho) # input files layupDataFilename = os.path.join(dataDir, "Winding_" + tankname + ".txt") materialFilename = os.path.join(dataDir, "CFRP_HyMod.json") domeContourFilename = os.path.join( dataDir, "Dome_contour_" + tankname + "_48mm.txt") # output files runDir = getRunDir() fileNameReducedDomeContour = os.path.join( runDir, f"Dome_contour_{tankname}_reduced.dcon") linerFilename = os.path.join(runDir, tankname + ".liner") designFilename = os.path.join(runDir, tankname + ".design") windingFile = os.path.join(runDir, tankname + "_realised_winding.txt") vesselFilename = os.path.join(runDir, tankname + ".vessel") windingResultFilename = os.path.join(runDir, tankname + ".wresults") print('runDir', runDir) print('dataDir', dataDir) #print(getLengthContourPath(domeContourFilename, 24., 51.175/2., 1)) # ######################################################################################### # Create Liner # ######################################################################################### x, r = getReducedDomePoints(domeContourFilename, dpoints, fileNameReducedDomeContour) dome = getDome(dzyl / 2., polarOpening, pychain.winding.DOME_TYPES.ISOTENSOID, x, r) liner = getLiner(dome, lzylinder, linerFilename, tankname) # ########################################### # Create material # ########################################### log.info(f'get material') material = getMaterial(materialFilename) angles, thicknesses, wendekreisradien, krempenradien = readLayupData( layupDataFilename) log.info(f'{angles[0:layersToWind]}') composite = getComposite(angles[0:layersToWind], thicknesses[0:layersToWind], hoopLayerThickness, helixLayerThickenss, material, sectionAreaFibre, rovingWidth, numberOfRovings, tex, designFilename, tankname) # create vessel and set liner and composite vessel = pychain.winding.Vessel() vessel.setLiner(liner) vessel.setComposite(composite) # ############################################################################# # run winding simulation # ############################################################################# # vessel.finishWinding() with open(windingFile, "w") as file: file.write('\t'.join(["Layer number", "Angle", "Polar opening"]) + '\n') outArr = [] vessel.resetWindingSimulation() anzHoop = 0. anzHelix = 0. for i, angle, krempenradius, wendekreisradius in zip( range(layersToWind), angles, krempenradien, wendekreisradien): # len(angle_degree) log.info('--------------------------------------------------') layerindex = i # Hoop Layer if abs(angle - 90.) < 1e-8: #po_goal = krempenradius po_goal = lzylinder / 2. - anzHoop * rovingWidth anzHoop = anzHoop + 1 #po_goal = wendekreisradius log.info( f'apply layer {i+1} with angle {angle}, Sollwendekreisradius {po_goal}' ) if optimizeWindingHoop: shift, err_wk, iterations = optimizeHoopShiftForPolarOpeningX( vessel, po_goal, layerindex) log.info( f'{iterations} iterations. Shift is {shift} resulting in a polar opening error of {err_wk} ' f'as current polar opening is {vessel.getPolarOpeningR(layerindex, True)}' ) else: # winding without optimization, but direct correction of shift vessel.setHoopLayerShift(layerindex, 0., True) vessel.runWindingSimulation(layerindex + 1) coor = po_goal - vessel.getPolarOpeningX(layerindex, True) vessel.setHoopLayerShift(layerindex, coor, True) vessel.runWindingSimulation(layerindex + 1) # Helix layer else: anzHelix = anzHelix + 1 # global arr_fric, arr_wk # global arr_fric, arr_wk # arr_fric = [] # arr_wk = [] po_goal = wendekreisradius log.info( f'apply layer {i+1} with band mid path at polar opening of {po_goal}' ) po_goal = getRadiusByShiftOnMandrel( vessel.getVesselLayer(layerindex - 1).getOuterMandrel1(), wendekreisradius, bandWidth) log.info( f'apply layer {i+1} with angle {angle} with band outer path at polar opening {po_goal}' ) log.info( f'radius difference is {po_goal-wendekreisradius}, {bandWidth}' ) # firts estimation with no frcition vessel.setLayerFriction(layerindex, 0., True) vessel.runWindingSimulation(layerindex + 1) log.info( f' polar opening with no friction is {vessel.getPolarOpeningR(layerindex, True)}' ) diff = vessel.getPolarOpeningR(layerindex, True) - po_goal if optimizeWindingHelical and abs(diff) > 0.: log.info(f'using optimizeFriction') #friction, err_wk, iterations = optimizeFriction(vessel, wendekreisradius, layerindex, verbose=False) #log.info(f'{iterations} iterations. Friction is {friction} resulting in a polar opening error of {err_wk} ' # f'as current polar opening is {vessel.getPolarOpeningR(layerindex, True)}') #po_local = vessel.getPolarOpeningR(layerindex, True) if diff > 0: log.info( f' current polar opening is too large, frcition musst be negative' ) log.info( f'using optimizeFrictionGlobal_differential_evolution') friction, err_wk, iterations = optimizeNegativeFrictionGlobal_differential_evolution( vessel, po_goal, layerindex, verbose=False) if diff < 0: log.info( f' current polar opening is too small, frcition musst be positive' ) log.info( f'using optimizeFrictionGlobal_differential_evolution') friction, err_wk, iterations = optimizeFrictionGlobal_differential_evolution( vessel, po_goal, layerindex, verbose=False) log.info( f'{iterations} iterations. Friction is {friction} resulting in a polar opening error of {err_wk} ' f'as current polar opening is {vessel.getPolarOpeningR(layerindex, True)}' ) if err_wk > 1.: log.info( f'!!!!! ERROR FOR POLAR OPEING IS LARGER THAN 1mm !!!') # file = open("data.txt", "w") # for j in range(len(arr_fric)): # file.write(str(arr_fric[j])+'\t'+str(arr_wk[j])+'\n') # file.close() # plt.plot(arr_fric, arr_wk, marker = 'o', linewidth = 0.) # m, n = fitting_linear(arr_fric,arr_wk) # log.info(m,n) # friction_corr = (wendekreisradius[i] - n) / m # vessel.setLayerFriction(layerindex, friction_corr, True) # vessel.runWindingSimulation(layerindex+1) # wk_korr = vessel.getPolarOpeningR(layerindex, True) # print (friction_corr, wk_korr) # y = linear(arr_fric, np.ones(len(arr_fric))*m, np.ones(len(arr_fric))*n) # plt.plot(arr_fric, y,'k--', lw = 1.) # plt.plot(friction_corr, wk_korr, 'ro') # plt.xlim((0., 0.0001)) # plt.ylim((25., 27.)) # plt.show() po = vessel.getPolarOpeningR(layerindex, True) outArr.append([i + 1, angle, po, po * 2, po_goal, abs(po - po_goal)]) with open(windingFile, "a") as file: file.write('\t'.join([str(s) for s in outArr[-1]]) + '\n') with open(windingFile, "w") as file: file.write( indent([[ "Layer \#", "Angle", "Polar opening", "Polar opening diameter", "Target Polar opening" ]] + outArr)) # save vessel vessel.saveToFile(vesselFilename) # save vessel updateName(vesselFilename, tankname, ['vessel']) # save winding results windingResults = pychain.winding.VesselWindingResults() windingResults.buildFromVessel(vessel) windingResults.saveToFile(windingResultFilename) # ############################################################################# # run internal calculation # ############################################################################# # build shell model for internal calculation converter = pychain.mycrofem.VesselConverter() shellModel = converter.buildAxShellModell(vessel, 10) # run linear solver linerSolver = pychain.mycrofem.LinearSolver(shellModel) linerSolver.run(True) # get stresses in the fiber COS S11, S22, S12 = shellModel.calculateLayerStressesBottom() # get x coordinates (element middle) xCoords = shellModel.getElementCoordsX() # ############################################################################# # run ABAQUS # ############################################################################# # create model options for abaqus calculation modelOptions = pychain.mycrofem.VesselFEMModelOptions() modelOptions.modelName = tankname + "_Vessel" modelOptions.jobName = tankname + "_Job" modelOptions.windingResultsFileName = tankname modelOptions.useMaterialPhi = False # false uses micromechanical estimations of fvg effect an porperties modelOptions.fittingContactWinding = pychain.mycrofem.CONTACT_TYPE.PENALTY modelOptions.frictionFitting = 0.3 modelOptions.globalMeshSize = 2.0 modelOptions.pressureInBar = servicepressure modelOptions.saveCAE = True modelOptions.buildMandrel1 = True modelOptions.buildMandrel2 = False # write abaqus scripts scriptGenerator = pychain.abaqus.AbaqusVesselScriptGenerator() scriptGenerator.writeVesselAxSolidBuildScript( os.path.join(runDir, tankname + "_Build.py"), settings, modelOptions) scriptGenerator.writeVesselAxSolidBuildScript( os.path.join(runDir, tankname + "_Eval.py"), settings, modelOptions) # create vessel model according to version 95_2 documentation 'Axis-Symmetric Vessel Model' #create vessel model vesselAxSolid = mymodels.myvesselAxSolidContacts model = vesselAxSolid.MyVesselAxSolid(modelName=tankname + "_Vessel", umat=True, buildFitting=True, saveCAE=True, useMaterialPhi=False, buildLiner=True) #load winding results model.loadData(tankname) #build mandrel 1 model.buildOnlyMandrel1( servicepressure, 1, friction=0.3, fittingContactWinding=pychain.mycrofem.CONTACT_TYPE.PENALT) #mesh model model.mesh(2.0) #export inp file model.exportInp(tankname + "_Job") import matplotlib.pylab as plt # fig = plt.figure() # ax = fig.gca() # ax.plot(S11[:, 0]) # ax.plot(S11[:, 1]) # ax.plot(S11[:, 2]) # plt.show() log.info('FINISHED')
def winding_helical_layer(friction, args): vessel, wendekreisradius = args log.info('--------------------') log.info(f'use friction {friction}') vessel.setLayerFriction(layerindex, abs(friction), True) log.info(f'set friction {friction}') try: vessel.runWindingSimulation(layerindex + 1) # log.info(f'apply layer {layerindex}') wk = vessel.getPolarOpeningR(layerindex, True) log.info(wk) except (IOError, ValueError, IOError, ZeroDivisionError): log.info('I have to pass') # log.info('this helical layer shoud end at', wendekreisradius[layerindex], 'mm but is at', wk, 'mm so there is a # deviation of', wendekreisradius[layerindex]-wk, 'mm') if abs(wendekreisradius[layerindex]-wk) < 2.: # arr_fric.append(abs(friction)) arr_wk.append(wk) return abs(wk - wendekreisradius[layerindex])
def main(): # ######################################################################################### # SET Parameters of vessel # ######################################################################################### tankname = 'NGT-BIT-2020-09-16' dataDir = os.path.join(programDir, 'data') dzyl = 400. # mm polarOpening = 20. # mm lzylinder = 500. # mm dpoints = 4 # data points for liner contour defaultLayerthickness = 0.125 hoopLayerThickness = 0.125 helixLayerThickenss = 0.129 bandWidth = 3.175 numberOfRovings = 1 rovingWidth = bandWidth / numberOfRovings tex = 446 # g / km rho = 1.78 # g / cm^3 sectionAreaFibre = tex / (1000. * rho) # ######################################################################################### # Create Liner # ######################################################################################### # load contour from file fileNameReducedDomeContour = os.path.join( dataDir, "Dome_contour_" + tankname + "_modified.dcon") Data = np.loadtxt( os.path.join(dataDir, "Dome_contour_" + tankname + ".txt")) if 0: contourPoints = np.abs(Data) contourPoints[:, 0] -= contourPoints[0, 0] #reduce points redContourPoints = contourPoints[::dpoints, :] if not np.allclose(redContourPoints[-1, :], contourPoints[-1, :]): redContourPoints = np.append(redContourPoints, [contourPoints[-1, :]], axis=0) np.savetxt(fileNameReducedDomeContour, redContourPoints, delimiter=',') Xvec, rVec = redContourPoints[:, 0], redContourPoints[:, 1] else: Xvec = abs(Data[:, 0]) Xvec = Xvec - Xvec[0] rVec = abs(Data[:, 1]) # reduce data points log.info(len(Xvec) - 1) index = np.linspace(0, dpoints * int((len(Xvec) / dpoints)), int((len(Xvec) / dpoints)) + 1, dtype=np.int16) arr = [len(Xvec) - 1] index = np.append(index, arr) Xvec = Xvec[index] rVec = rVec[index] # save liner contour for loading in mikroWind with open(fileNameReducedDomeContour, "w") as contour: for i in range(len(Xvec)): contour.write(str(Xvec[i]) + ',' + str(rVec[i]) + '\n') # build dome dome = pychain.winding.Dome() dome.buildDome(dzyl / 2., polarOpening, pychain.winding.DOME_TYPES.ISOTENSOID) dome.setPoints(Xvec, rVec) log.info(f'Build Dome with dome data {dome}') # create a symmetric liner with dome information and cylinder length liner = pychain.winding.Liner() # spline for winding calculation is left on default of 1.0 liner.buildFromDome(dome, lzylinder, 1.0) # save liner for visualization with µChainWind linerFilename = os.path.join(dataDir, tankname + ".liner") liner.saveToFile(linerFilename) log.info('saved liner') # change name of liner in file with open(linerFilename) as jsonFile: data = json.load(jsonFile) data["liner"]["name"] = tankname with open(linerFilename, "w") as jsonFile: json.dump(data, jsonFile, indent=4) # copyfile(tankname+"_.liner", tankname+'_copy.liner') # fobj = open(tankname+"_copy.liner") # fobj_new = open(tankname+"_.liner", "w") # for line in fobj: # if line[9:13]=='name': # print ('change name from '+line+' to '+tankname) # fobj_new.write('\t\t"name": "'+tankname+'", \n') # else: # fobj_new.write(line) # fobj.close() # fobj_new.close() # os.remove(tankname+"_copy.liner") # ########################################### # Create winding # ########################################### # create default material # t700 = pychain.material.OrthotropMaterial() # t700.setDefaultCFRP() # load material material = pychain.material.OrthotropMaterial() material.loadFromFile(os.path.join(dataDir, "CFRP_HyMod.json")) mat = pychain.material # read winding angles in cylindrical regime Data = np.loadtxt(os.path.join(dataDir, "Winding_" + tankname + ".txt")) angle_degree = abs(Data[:, 0]) wendekreisdurchmesser = abs(Data[:, 1]) wendekreisradius = wendekreisdurchmesser / 2. singlePlyThickenss = abs(Data[:, 2]) krempendruchmesser = abs(Data[:, 3]) krempenradius = krempendruchmesser / 2. # create composite with layers composite = pychain.material.Composite() for i in range(len(angle_degree)): # angle = angle_degree[i] composite.appendLayer(angle, singlePlyThickenss[i], material, pychain.material.LAYER_TYPES.BAP) fvg = sectionAreaFibre / (bandWidth * singlePlyThickenss[i]) composite.getOrthotropLayer(i).phi = fvg if angle == 90.: # change winding properties composite.getOrthotropLayer( i).windingProperties.rovingWidth = rovingWidth composite.getOrthotropLayer( i).windingProperties.numberOfRovings = numberOfRovings composite.getOrthotropLayer(i).windingProperties.texNumber = tex composite.getOrthotropLayer(i).windingProperties.coverage = 1. composite.getOrthotropLayer(i).windingProperties.isHoop = True composite.getOrthotropLayer( i).windingProperties.cylinderThickness = hoopLayerThickness else: # change winding properties composite.getOrthotropLayer( i).windingProperties.rovingWidth = rovingWidth composite.getOrthotropLayer( i).windingProperties.numberOfRovings = numberOfRovings composite.getOrthotropLayer(i).windingProperties.texNumber = tex composite.getOrthotropLayer(i).windingProperties.coverage = 1. composite.getOrthotropLayer( i).windingProperties.cylinderThickness = helixLayerThickenss composite.updateThicknessFromWindingProperties() composite.saveToFile(tankname + ".design") # rename design with open(os.path.join(dataDir, tankname + ".design")) as jsonFile: data = json.load(jsonFile) data["designs"]["1"]["name"] = tankname with open(os.path.join(dataDir, tankname + ".design"), "w") as jsonFile: json.dump(data, jsonFile, indent=4) # create vessel and set liner and composite vessel = pychain.winding.Vessel() vessel.setLiner(liner) vessel.setComposite(composite) # ############################################################################# # run winding simulation # ############################################################################# # vessel.finishWinding() global layerindex with open(os.path.join(dataDir, tankname + "_realised_winding.txt"), "w") as file: file.write("Layer number" + '\t' + "Angle" + '\t' + "Polar opening" + '\n') vessel.resetWindingSimulation() for i in range(3): # len(angle_degree) log.info('--------------------------------------------------') log.info(f'apply layer {i + 1} with angle {angle_degree[i]}') layerindex = i # wk = winding_layer(i, 0.5) if angle_degree[i] == 90.: log.info(f'Sollwendekreisradius {krempenradius[i]}') shift, err_wk = optimze_winding_parameters_shift( vessel, krempenradius, layerindex) log.info( f'optimised shift is {shift} resulting in a polar opening error of {err_wk} ' f'as current polar opening is {vessel.getPolarOpeningR(layerindex, True)}' ) else: # global arr_fric, arr_wk # global arr_fric, arr_wk # arr_fric = [] # arr_wk = [] log.info(f'Sollwendekreisradius {wendekreisradius[i]}') friction, err_wk = optimze_winding_parameters_friction( vessel, wendekreisradius) log.info( f'optimised friction is {friction} resulting in a polar opening error of {err_wk}' f'as current polar opening is {vessel.getPolarOpeningR(layerindex, True)}' ) # file = open("data.txt", "w") # for j in range(len(arr_fric)): # file.write(str(arr_fric[j])+'\t'+str(arr_wk[j])+'\n') # file.close() # plt.plot(arr_fric, arr_wk, marker = 'o', linewidth = 0.) # m, n = fitting_linear(arr_fric,arr_wk) # log.info(m,n) # friction_corr = (wendekreisradius[i] - n) / m # vessel.setLayerFriction(layerindex, friction_corr, True) # vessel.runWindingSimulation(layerindex+1) # wk_korr = vessel.getPolarOpeningR(layerindex, True) # print (friction_corr, wk_korr) # y = linear(arr_fric, np.ones(len(arr_fric))*m, np.ones(len(arr_fric))*n) # plt.plot(arr_fric, y,'k--', lw = 1.) # plt.plot(friction_corr, wk_korr, 'ro') # plt.xlim((0., 0.0001)) # plt.ylim((25., 27.)) # plt.show() file.write( str(i + 1) + '\t' + str(angle_degree[i]) + '\t' + str(vessel.getPolarOpeningR(layerindex, True)) + '\n') # save vessel vessel.saveToFile(os.path.join(dataDir, tankname + ".vessel")) # save vessel with open(os.path.join(dataDir, tankname + ".vessel")) as jsonFile: data = json.load(jsonFile) data["vessel"]["name"] = tankname with open(os.path.join(dataDir, tankname + ".vessel"), "w") as jsonFile: json.dump(data, jsonFile, indent=4) # rename vessel # save winding results windingResults = pychain.winding.VesselWindingResults() windingResults.buildFromVessel(vessel) windingResults.saveToFile(os.path.join(dataDir, tankname + ".wresults")) # build shell model for internal calculation converter = pychain.mycrofem.VesselConverter() shellModel = converter.buildAxShellModell(vessel, 10) # run linear solver linerSolver = pychain.mycrofem.LinearSolver(shellModel) linerSolver.run(True) # get stresses in the fiber COS S11, S22, S12 = shellModel.calculateLayerStressesBottom() # get x coordinates (element middle) xCoords = shellModel.getElementCoordsX() # create model options for abaqus calculation modelOptions = pychain.mycrofem.VesselFEMModelOptions() modelOptions.modelName = tankname + "_Vessel" modelOptions.jobName = tankname + "_Job" modelOptions.windingResultsFileName = tankname modelOptions.useMaterialPhi = False modelOptions.fittingContactWinding = pychain.mycrofem.CONTACT_TYPE.PENALTY modelOptions.globalMeshSize = 0.25 modelOptions.pressureInBar = 300.0 # write abaqus scripts scriptGenerator = pychain.abaqus.AbaqusVesselScriptGenerator() scriptGenerator.writeVesselAxSolidBuildScript( os.path.join(dataDir, tankname + "_Build.py"), settings, modelOptions) scriptGenerator.writeVesselAxSolidBuildScript( os.path.join(dataDir, tankname + "_Eval.py"), settings, modelOptions) import matplotlib.pylab as plt fig = plt.figure() ax = fig.gca() ax.plot(S11[:, 0]) ax.plot(S11[:, 1]) ax.plot(S11[:, 2]) plt.show() log.info('FINISHED')
def printLayer(layerNumber, verbose=False): sep = '\n' + '=' * 80 log.info((sep if verbose else '') + f'\nLayer {layerNumber}' + (sep if verbose else ''))
def designLayers(vessel, maxLayers, minPolarOpening, puckProperties, burstPressure, runDir, composite, compositeArgs, verbose): """ Strategy: #. Start with hoop layer #. Second layer: #. Maximize layer angle that still attaches to the fitting #. add layer with this angle #. Iteratively perform the following #. Get puck fibre failures #. Check if puck reserve factors are satisfied - if yes end iteration #. Reduce relevant locations to #. 1 element at cylindrical section and #. every element between polar opening radii of 0 and of 70° angle layers #. identify critical element #. if critical element is in cylindrical section #. add hoop layer #. next iteration step #. if most loaded element is in dome area: #. Define Optimization bounds [minAngle, 70°] and puck result bounds #. Minimize puck fibre failue: #. Set angle #. Use analytical linear solver #. return max puck fibre failure #. Apply optimal angle to actual layer #. next iteration step """ vessel.resetWindingSimulation() anglesShifts = [] # list of 2-tuple with angle and shift for each layer show = False save = True layerNumber = 0 iterations = 0 liner = vessel.getLiner() dome = liner.getDome1() radiusDropThreshold = windLayer(vessel, layerNumber, 70) mandrel = vessel.getVesselLayer(layerNumber).getOuterMandrel1() dropRadiusIndex = np.argmin( np.abs(mandrel.getRArray() - radiusDropThreshold)) elementCount = mandrel.getRArray().shape[0] - 1 minAngle, _, _ = optimizeAngle( vessel, minPolarOpening, layerNumber, 1., False, targetFunction=getAngleAndPolarOpeningDiffByAngle) rMax = mandrel.getRArray()[0] dropHoopIndexStart = np.argmax( (-mandrel.getRArray() + rMax) > rMax * 1e-4) - 10 dropHoopIndexEnd = np.argmin( np.abs(mandrel.getRArray() - dome.cylinderRadius * 0.98)) hoopOrHelicalIndex = np.argmin( np.abs(mandrel.getRArray() - dome.cylinderRadius * 0.99)) maxHoopShift = mandrel.getLArray( )[dropHoopIndexEnd] - liner.cylinderLength / 2 dropHoopIndicies = list(range(0, dropHoopIndexStart)) + list( range(dropHoopIndexEnd, elementCount)) dropHelicalIndicies = range(0, hoopOrHelicalIndex) # introduce layer up to the fitting. Optimize required angle printLayer(layerNumber, verbose) angle, _, _ = optimizeAngle( vessel, minPolarOpening, layerNumber, minAngle, False, targetFunction=getNegAngleAndPolarOpeningDiffByAngle) anglesShifts.append((angle, 0)) layerNumber += 1 # add hoop layer resHoop = optimizeHoop(vessel, layerNumber, puckProperties, burstPressure, dropHoopIndicies, maxHoopShift, verbose) shift, funcVal, loopIt, newDesignIndex = resHoop windHoopLayer(vessel, layerNumber, shift) anglesShifts.append((90, shift)) #printLayer(layerNumber, verbose) #windLayer(vessel, layerNumber, 90) #anglesShifts.append((90.,0)) # create other layers for layerNumber in range(layerNumber + 1, maxLayers): printLayer(layerNumber, verbose) elemIdxmax, puckFF = getCriticalElementIdxAndPuckFF( vessel, puckProperties, None, burstPressure) if puckFF.max().max() < 1: if verbose: log.info('End Iteration') # stop criterion reached columns = [ 'lay{}_{:04.1f}'.format(i, angle) for i, (angle, _) in enumerate(anglesShifts) ] puckFF.columns = columns plotDataFrame(False, os.path.join(runDir, f'puck_{layerNumber}.png'), puckFF) layerNumber -= 1 break elif layerNumber > maxLayers: raise Tankoh2Error( 'Reached max layers. You need to specify more initial layers') # add one layer composite = getComposite([a for a, _ in anglesShifts] + [90], [compositeArgs[2]] * (layerNumber + 1), *compositeArgs[1:]) vessel.setComposite(composite) resetVesselAnglesShifts(anglesShifts, vessel) # check zone of highest puck values if elemIdxmax < hoopOrHelicalIndex: resHoop = optimizeHoop(vessel, layerNumber, puckProperties, burstPressure, dropHoopIndicies, maxHoopShift, verbose) resHelical = optimizeHelical(vessel, layerNumber, puckProperties, burstPressure, minPolarOpening, dropHoopIndicies, verbose) if resHoop[1] < resHelical[ 1] * 1.25: # puck result with helical layer must be 1.25 times better # add hoop layer shift, funcVal, loopIt, newDesignIndex = resHoop windHoopLayer(vessel, layerNumber, shift) anglesShifts.append((90, shift)) else: angle, funcVal, loopIt, newDesignIndex = resHelical windLayer(vessel, layerNumber, angle) anglesShifts.append((angle, 0)) else: angle, funcVal, loopIt, newDesignIndex = optimizeHelical( vessel, layerNumber, puckProperties, burstPressure, minPolarOpening, dropHelicalIndicies, verbose) anglesShifts.append((angle, 0)) iterations += loopIt columns = [ 'lay{}_{:04.1f}'.format(i, angle) for i, (angle, _) in enumerate(anglesShifts[:-1]) ] puckFF.columns = columns plotDataFrame(False, os.path.join(runDir, f'puck_{layerNumber}.png'), puckFF, None, vlines=[elemIdxmax, hoopOrHelicalIndex, newDesignIndex], vlineColors=['red', 'black', 'green'], title='puck fibre failure') vessel.finishWinding() results = getLinearResults(vessel, puckProperties, layerNumber, burstPressure) if show or save: plotStressEpsPuck( show, os.path.join(runDir, f'sig_eps_puck_{layerNumber}.png') if save else '', *results) thicknesses = getLayerThicknesses(vessel) columns = [ 'lay{}_{:04.1f}'.format(i, angle) for i, (angle, _) in enumerate(anglesShifts) ] thicknesses.columns = columns plotDataFrame(show, os.path.join(runDir, f'thicknesses_{getTimeString()}.png'), thicknesses, title='layer thicknesses') # get volume and surface area stats = vessel.calculateVesselStatistics() frpMass = stats.overallFRPMass # in [kg] volume = liner.getVolume() # [l] r, x = dome.getRCoords(), dome.getXCoords() areaDome = np.pi * (r[:-1] + r[1:]) * np.sqrt((r[:-1] - r[1:])**2 + (x[:-1] - x[1:])**2) area = 2 * np.pi * liner.cylinderRadius * liner.cylinderLength + 2 * np.sum( areaDome) # [mm**2] area *= 1e-6 # [m**2] return frpMass, volume, area, composite, iterations, anglesShifts
def createWindingDesign(**kwargs): startTime = datetime.datetime.now() verbose = False # ######################################################################################### # SET Parameters of vessel # ######################################################################################### log.info('=' * 100) log.info('createWindingDesign with these parameters: ' + str(kwargs)) log.info('=' * 100) # design constants AND not recognized issues # band pattern not recognized layersToWind = 100 tankname = 'exact_h2' dataDir = os.path.join(programDir, 'data') hoopLayerThickness = 0.125 helixLayerThickenss = 0.129 rovingWidth = 3.175 numberOfRovings = 4 bandWidth = rovingWidth * numberOfRovings tex = 446 # g / km rho = 1.78 # g / cm^3 sectionAreaFibre = tex / (1000. * rho) pressure = 5. # pressure in MPa (bar / 10.) safetyFactor = 2.25 # potential external inputs burstPressure = kwargs.get('burstPressure', pressure * safetyFactor) dzyl = kwargs.get('dzyl', 400.) # mm minPolarOpening = kwargs.get('minPolarOpening', 20) # mm domeType = kwargs.get( 'domeType', pychain.winding.DOME_TYPES.ISOTENSOID) # CIRCLE; ISOTENSOID runDir = kwargs['runDir'] if 'runDir' in kwargs else getRunDir() if 'lzyl' in kwargs: lzylinder = kwargs.get('lzyl', 500.) # mm else: lzylByR = kwargs.get('lzylByR', 2.5) # mm lzylinder = lzylByR * dzyl / 2 if 0: # test pressure vessel vs cryo vessel dzyl = 2000 #mm lzylinder = 4000 #mm minPolarOpening = dzyl / 2 / 10 burstPressure = 25 runDir = kwargs.get('runDir', getRunDir(f'_{burstPressure}MPa')) # input files materialFilename = os.path.join(dataDir, "CFRP_HyMod.json") # output files linerFilename = os.path.join(runDir, tankname + ".liner") designFilename = os.path.join(runDir, tankname + ".design") vesselFilename = os.path.join(runDir, tankname + ".vessel") windingResultFilename = os.path.join(runDir, tankname + ".wresults") # ######################################################################################### # Create Liner # ######################################################################################### dome = getDome(dzyl / 2., minPolarOpening, domeType) liner = getLiner(dome, lzylinder, linerFilename, tankname) # ########################################### # Create material # ########################################### material = getMaterial(materialFilename) puckProperties = material.puckProperties angles, thicknesses, = [90.] * 2, [helixLayerThickenss] * 2 compositeArgs = [ thicknesses, hoopLayerThickness, helixLayerThickenss, material, sectionAreaFibre, rovingWidth, numberOfRovings, tex, designFilename, tankname ] composite = getComposite(angles, *compositeArgs) # create vessel and set liner and composite vessel = pychain.winding.Vessel() vessel.setLiner(liner) vessel.setComposite(composite) # ############################################################################# # run winding simulation # ############################################################################# vessel.saveToFile(vesselFilename) # save vessel frpMass, volume, area, composite, iterations, anglesShifts = designLayers( vessel, layersToWind, minPolarOpening, puckProperties, burstPressure, runDir, composite, compositeArgs, verbose) np.savetxt(os.path.join(runDir, 'angles_shifts.txt'), anglesShifts) # save vessel vessel.saveToFile(vesselFilename) # save vessel updateName(vesselFilename, tankname, ['vessel']) updateName(vesselFilename, pressure, ['vessel'], attrName='operationPressure') updateName(vesselFilename, safetyFactor, ['vessel'], attrName='securityFactor') copyAsJson(vesselFilename, 'vessel') # save winding results windingResults = pychain.winding.VesselWindingResults() windingResults.buildFromVessel(vessel) windingResults.saveToFile(windingResultFilename) copyAsJson(windingResultFilename, 'wresults') # ############################################################################# # run Evaluation # ############################################################################# if 0: results = getLinearResults(vessel, puckProperties, layersToWind - 1, burstPressure) plotStressEpsPuck(True, None, *results) if verbose: # vessel.printSimulationStatus() composite.info() duration = datetime.datetime.now() - startTime log.info(f'iterations {iterations}, runtime {duration.seconds} seconds') log.info('FINISHED') resultNames = [ 'frpMass', 'volume', 'area', 'lzylinder', 'numberOfLayers', 'angles' ] results = frpMass, volume, area, liner.linerLength, composite.getNumberOfLayers( ), [a for a, _ in anglesShifts] with open(os.path.join(runDir, 'results.txt'), 'w') as f: f.write(indent([resultNames, results])) return results