Skip to content
Snippets Groups Projects
Commit 5da7e01a authored by Sam Calisch's avatar Sam Calisch
Browse files

added flexure specification sim

parent 8912789e
No related branches found
No related tags found
No related merge requests found
Pipeline #
python flexure_stiffness.py -Q -M simulate -f 15 -flexure_type cyclic -w .0007 -t .0015 -l .010
#!/usr/bin/env python
from __future__ import division
from numpy import *
import argparse
from pyframe3dd.frame3dd import write_frame3dd_file, read_lowest_mode, read_frame3dd_displacements, compute_mass
from pyframe3dd.util import magnitudes, close
import subprocess
def plot_connections(nodes,beamsets):
#for debug only, this is slow!
import matplotlib as mpl
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
cmap = plt.cm.get_cmap('Dark2', len(beamsets)+1)
ax = fig.gca(projection='3d')
for i,beamset in enumerate(beamsets):
for seg in beamset:
ax.plot(nodes[seg,0], nodes[seg,1], nodes[seg,2], c=cmap(i))
plt.show()
def run_frame3dd(args,nodes,global_args,beam_sets,constraints,loads):
write_frame3dd_file(nodes,global_args,beam_sets,constraints,loads)
cmd = ["frame3dd", "-i",global_args['frame3dd_filename']+'.csv']
if args.quiet: cmd.append("-q")
print ' '.join(cmd)
subprocess.call(cmd)
def clean_up_frame3dd(filename):
#Delete files generated by frame3dd
files = [filename+end for end in ["_out.csv",".csv.out",".csv.plt",".csv.if01",".csv"]]
subprocess.call(["rm"]+files)
def build(args):
#return nodes,rods as numpy arrays
dxy = args.attach_radius/sqrt(2)
if args.flexure_type == 'mirrored':
nodes = args.l*array([[0,0,0],[0,1,0],[-1,1,0],[1,0,0],[1,-1,0]]) #one side of flexure plate
beams = array([[0,1],[1,2],[0,3],[3,4]])
nodes += array([dxy,dxy,0]) #offset by attachment radius
elif args.flexure_type == 'cyclic':
nodes = args.l*array([[0,0,0],[0,1,0],[-1,1,0]]) + array([dxy,dxy,0])
beams = array([[0,1],[1,2],[3,4]])
nodes = vstack((nodes, args.l*array([[1,1,0],[1,0,0]]) + array([dxy,-dxy,0])))
nodes = vstack((nodes,array([[-n[0],-n[1],0] for n in nodes]))) #append reflection
beams = vstack((beams, beams + 5))
z_os = array([0,0,.5*args.sep])
nodes = vstack((nodes + z_os, nodes - z_os))
beams = vstack((beams, beams + 10))
solid_nodes = array([ [dxy,-dxy,.5*args.sep],[-dxy,dxy,.5*args.sep],[dxy,-dxy,-.5*args.sep],[-dxy,dxy,-.5*args.sep] ])
nodes = vstack((nodes, solid_nodes))
solid_beams = array([
[0,5],[0,10],[5,15],[10,15],#[0,15],[5,10],
[0,20],[0,21],[5,20],[5,21],[20,21],
[10,22],[10,23],[15,22],[15,23],[22,23],
[20,22],[21,23],#[20,23],[21,22],
[0,22],[0,23],[5,22],[5,23],
[10,20],[10,21],[15,20],[15,21]
])
if args.flexure_type == 'cyclic':
beams = vstack((beams, array([[4,20],[9,21],[14,22],[19,23]])))
return nodes, beams, solid_beams
def run_simulation(args):
#set up simulation
nodes,beams,solid_beams = build(args)
global_args = {
'n_modes':args.n_modes,'length_scaling':args.length_scaling,'exagerration':10,
'node_radius':zeros(shape(nodes)[0]),'frame3dd_filename':args.base_filename+"_frame3dd"
}
clean_up_frame3dd(global_args['frame3dd_filename'])
beam_sets = [
(beams,{'E':args.E,'nu':args.nu,'rho':args.rho,'cross_section':'rectangular','d2':args.w,'d1':args.t,'roll':0.,'loads':[],'beam_divisions':args.bd,'prestresses':[]}),
(solid_beams,{'E':10*args.E,'nu':args.nu,'rho':args.rho,'cross_section':'rectangular','d1':args.w,'d2':args.t,'roll':0.,'loads':[],'beam_divisions':args.bd,'prestresses':[]})
]
if args.flexure_type == 'mirrored':
fixed_nodes = [2,4,7,9,12,14,17,19]
elif args.flexure_type == 'cyclic':
fixed_nodes = [2,3,7,8,12,13,17,18]
constraints = [{'node':node,'DOF':dof,'value':0} for dof in [0,1,2,3,4,5] for node in fixed_nodes]
for force_dof in [0,1,2]:
loaded_nodes = [0,5,10,15]
loads = [{'node':n,'DOF':force_dof,'value':args.force/len(loaded_nodes)} for n in loaded_nodes]
run_frame3dd(args,nodes,global_args,beam_sets,constraints,loads)
results = {}
results['beam_mass'] = compute_mass(nodes,beam_sets)
disps = read_frame3dd_displacements(global_args['frame3dd_filename'])
force_disp = average(disps[loaded_nodes,force_dof])
print "Degree of freedom: %d"%force_dof
print "Force applied: %.1f N"%(args.force)
print "Calculated displacement: %.1f microns"%(force_disp*1e6)
#todo: read average displacement of loaded nodes
#todo: plot displacements vs. design parameters
#results['fundamental_frequency'] = read_lowest_mode(global_args['frame3dd_filename']+'.csv')
return results
def find_stability_threshold(args):
#out loop of simulations to determine the buckling load
lower = 0 #lower bound
upper = 10*args.force_res #initial upper bound before bracketing
bracketed=False
#actually not necessary, but fun to have the unloaded frequency
args.force = lower
res = run_simulation(args)
freqs = [res['fundamental_frequency']]
forces = [args.force]
i = 0
while not bracketed:
print lower,upper,bracketed,res['fundamental_frequency']
args.force = upper
res = run_simulation(args); i += 1
if res['fundamental_frequency']<0:
bracketed=True
else:
freqs.append(res['fundamental_frequency'])
forces.append(args.force)
lower = upper
upper = 2*upper
while (upper-lower > args.force_res):
print lower,upper,bracketed
args.force = .5*(upper+lower)
res = run_simulation(args); i += 1
if res['fundamental_frequency']>0:
freqs.append(res['fundamental_frequency'])
forces.append(args.force)
lower = .5*(upper+lower)
else:
upper = .5*(upper+lower)
return forces,freqs,res
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-M','--mode',choices=('simulate','search', 'visualize'), required=True)
parser.add_argument('-flexure_type','--flexure_type',choices=('cyclic','mirrored'), required=True)
parser.add_argument('-Q','--quiet',action='store_true',help='Whether to suppress frame3dd output')
parser.add_argument("-f","--force", type=double, default=.1, help="force to apply")
#parser.add_argument("-fr","--force_res", type=double, default=.01, help="Final resolution of force for search mode")
parser.add_argument("-w","--w", type=double, default=.0005, help="width of flexure (m)")
parser.add_argument("-t","--t", type=double, default=.0023, help="thickness of flexure material (m)")
parser.add_argument("-l","--l", type=double, default=.0068, help="length of flexure segment (m)")
parser.add_argument("-attach_radius","--attach_radius", type=double, default=.0043, help="distance from z axis to flexure attachment (m)")
parser.add_argument("-sep","--sep", type=double, default=.025, help="flexure plate z separation (m)")
parser.add_argument("-bd","--bd", type=int, default=1, help='how many divisions for each rod, useful in buckling analysis')
parser.add_argument("-E","--E", type=double, default=70e9, help="Young's Modulus of laminate")
parser.add_argument("-nu","--nu", type=double, default=.33, help="Poisson Ratio")
parser.add_argument("-base_filename","--base_filename", default='buckle', help="Base filename for segments and frame3dd")
parser.add_argument("-rho","--rho",type=double,default=2700.,help='density of beam material, kg/m^3')
parser.add_argument("-n_modes","--n_modes",type=int,default=0,help='number of dynamic modes to compute')
parser.add_argument("-ls","--length_scaling", type=double, default=1., help="Scale factor to keep numbers commesurate")
args = parser.parse_args()
if args.mode=='search':
forces,freqs,last_res = find_stability_threshold(args)
print "Fundamental frequency: %.3f Hz"%(freqs[-1])
print "Critical force: %.3f N"%(forces[-1])
print "Critical stress: %.3f MPa"%(last_res['stress']/1e6)
elif args.mode=='simulate':
res = run_simulation(args)
#print "Fundamental frequency: %.3f Hz"%res['fundamental_frequency']
#print "Stress: %.3f MPa"%(res['stress']/1e6)
elif args.mode=='visualize':
nodes,rods,solid_beams = build(args)
plot_connections(nodes,[rods,solid_beams])
else:
assert(0) #should not be here
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment