-
Amira Abdel-Rahman authoredAmira Abdel-Rahman authored
dynamicFriction.jl 53.97 KiB
# Amira Abdel-Rahman
# (c) Massachusetts Institute of Technology 2020
using LinearAlgebra
using Plots
import JSON
# using Quaternions
using StaticArrays
# using Distributed, Rotations
using StaticArrays, BenchmarkTools
using Base.Threads
using CUDAnative
using CuArrays,CUDAdrv
using Test
import Base: +, * , -, ^
#####################################################
struct Vector3
x::Float64
y::Float64
z::Float64
function Vector3()
x=0.0
y=0.0
z=0.0
new(x,y,z)
end
function Vector3(x,y,z)
new(x,y,z)
end
end
struct Quaternion
x::Float64
y::Float64
z::Float64
w::Float64
function Quaternion()
x=0.0
y=0.0
z=0.0
w=1.0
new(x,y,z,w)
end
function Quaternion(x,y,z,w)
new(x,y,z,w)
end
end
struct RotationMatrix
te1::Float64
te2::Float64
te3::Float64
te4::Float64
te5::Float64
te6::Float64
te7::Float64
te8::Float64
te9::Float64
te10::Float64
te11::Float64
te12::Float64
te13::Float64
te14::Float64
te15::Float64
te16::Float64
function RotationMatrix()
te1 =0.0
te2 =0.0
te3 =0.0
te4 =0.0
te5 =0.0
te6 =0.0
te7 =0.0
te8 =0.0
te9 =0.0
te10=0.0
te11=0.0
te12=0.0
te13=0.0
te14=0.0
te15=0.0
te16=0.0
new(te1,te2,te3,te4,te5,te6,te7,te8,te9,te10,te11,te12,te13,te14,te15,te16)
end
function RotationMatrix(te1,te2,te3,te4,te5,te6,te7,te8,te9,te10,te11,te12,te13,te14,te15,te16)
new(te1,te2,te3,te4,te5,te6,te7,te8,te9,te10,te11,te12,te13,te14,te15,te16)
end
end
+(f::Vector3, g::Vector3)=Vector3(f.x+g.x , f.y+g.y,f.z+g.z )
-(f::Vector3, g::Vector3)=Vector3(f.x-g.x , f.y-g.y,f.z-g.z )
*(f::Vector3, g::Vector3)=Vector3(f.x*g.x , f.y*g.y,f.z*g.z )
+(f::Vector3, g::Number)=Vector3(f.x+g , f.y+g,f.z+g )
-(f::Vector3, g::Number)=Vector3(f.x-g , f.y-g,f.z-g )
*(f::Vector3, g::Number)=Vector3(f.x*g , f.y*g,f.z*g )
+(g::Vector3, f::Number)=Vector3(f.x+g , f.y+g,f.z+g )
-(g::Vector3, f::Number)=Vector3(g-f.x , g-f.y,g-f.z )
*(g::Vector3, f::Number)=Vector3(f.x*g , f.y*g,f.z*g )
addX(f::Vector3, g::Number)=Vector3(f.x+g , f.y,f.z)
addY(f::Vector3, g::Number)=Vector3(f.x , f.y+g,f.z )
addZ(f::Vector3, g::Number)=Vector3(f.x , f.y,f.z+g )
function normalizeVector3(f::Vector3)
leng=sqrt((f.x * f.x) + (f.y * f.y) + (f.z * f.z))
return Vector3(f.x/leng,f.y/leng,f.z/leng)
end
function normalizeQuaternion(f::Quaternion)
l = sqrt((f.x * f.x) + (f.y * f.y) + (f.z * f.z)+ (f.w * f.w))
if l === 0
qx = 0
qy = 0
qz = 0
qw = 1
else
l = 1 / l
qx = f.x * l
qy = f.y * l
qz = f.z * l
qw = f.w * l
end
return Quaternion(qx,qy,qz,qw)
end
function normalizeQuaternion1!(fx::Float64,fy::Float64,fz::Float64,fw::Float64)
l = sqrt((fx * fx) + (fy * fy) + (fz * fz)+ (fw * fw))
if l === 0
qx = 0.0
qy = 0.0
qz = 0.0
qw = 1.0
else
l = 1.0 / l
qx = fx * l
qy = fy * l
qz = fz * l
qw = fw * l
end
return qx,qy,qz,qw
end
function dotVector3(f::Vector3, g::Vector3)
return (f.x * g.x) + (f.y * g.y) + (f.z * g.z)
end
function Base.show(io::IO, v::Vector3)
print(io, "x:$(v.x), y:$(v.y), z:$(v.z)")
end
function Base.show(io::IO, v::Quaternion)
print(io, "x:$(v.x), y:$(v.y), z:$(v.z), w:$(v.z)")
end
Base.Broadcast.broadcastable(q::Vector3) = Ref(q)
#####################################################
function doTimeStep!(metavoxel,dt,currentTimeStep)
# update forces: go through edges, get currentposition from nodes, calc pos2 and update stresses and interior forces of nodes
run_updateEdges!(
metavoxel["E_sourceGPU"],
metavoxel["E_targetGPU"],
metavoxel["E_areaGPU"],
metavoxel["E_densityGPU"],
metavoxel["E_stiffnessGPU"],
metavoxel["E_stressGPU"],
metavoxel["E_axisGPU"],
metavoxel["E_currentRestLengthGPU"],
metavoxel["E_pos2GPU"],
metavoxel["E_angle1vGPU"],
metavoxel["E_angle2vGPU"],
metavoxel["E_angle1GPU"],
metavoxel["E_angle2GPU"],
metavoxel["E_intForce1GPU"],
metavoxel["E_intMoment1GPU"],
metavoxel["E_intForce2GPU"],
metavoxel["E_intMoment2GPU"],
metavoxel["E_dampGPU"],
metavoxel["N_currPositionGPU"],
metavoxel["N_orientGPU"])
# update forces: go through nodes and update interior force (according to int forces from edges), integrate and update currpos
run_updateNodes!(dt,currentTimeStep,
metavoxel["N_positionGPU"],
metavoxel["N_restrainedGPU"],
metavoxel["N_displacementGPU"],
metavoxel["N_angleGPU"],
metavoxel["N_currPositionGPU"],
metavoxel["N_linMomGPU"],
metavoxel["N_angMomGPU"],
metavoxel["N_intForceGPU"],
metavoxel["N_intMomentGPU"],
metavoxel["N_forceGPU"],
metavoxel["N_momentGPU"],
metavoxel["N_orientGPU"],
metavoxel["N_edgeIDGPU"],
metavoxel["N_edgeFirstGPU"],
metavoxel["E_intForce1GPU"],
metavoxel["E_intMoment1GPU"],
metavoxel["E_intForce2GPU"],
metavoxel["E_intMoment2GPU"])
end
#####################################################
function updateEdges!(E_source,E_target,E_area,E_density,E_stiffness,E_stress,E_axis,E_currentRestLength,E_pos2,E_angle1v,E_angle2v,E_angle1,E_angle2,E_intForce1,E_intMoment1,E_intForce2,E_intMoment2,E_damp,N_currPosition,N_orient)
index = (blockIdx().x - 1) * blockDim().x + threadIdx().x
stride = blockDim().x * gridDim().x
## @cuprintln("thread $index, block $stride")
N=length(E_source)
for i = index:stride:N
@inbounds pVNeg=N_currPosition[E_source[i]]
@inbounds pVPos=N_currPosition[E_target[i]]
@inbounds oVNeg=N_orient[E_source[i]]
@inbounds oVPos=N_orient[E_target[i]]
@inbounds oldPos2=Vector3(E_pos2[i].x,E_pos2[i].y,E_pos2[i].z) #?copy?
@inbounds oldAngle1v = Vector3(E_angle1v[i].x,E_angle1v[i].y,E_angle1v[i].z)
@inbounds oldAngle2v = Vector3(E_angle2v[i].x,E_angle2v[i].y,E_angle2v[i].z)# remember the positions/angles from last timestep to calculate velocity
@inbounds E_pos2[i],E_angle1v[i],E_angle2v[i],E_angle1[i],E_angle2[i],totalRot= orientLink!(E_currentRestLength[i],pVNeg,pVPos,oVNeg,oVPos,E_axis[i])
@inbounds dPos2 = Vector3(0.5,0.5,0.5) * (E_pos2[i]-oldPos2) #deltas for local damping. velocity at center is half the total velocity
@inbounds dAngle1 = Vector3(0.5,0.5,0.5) *(E_angle1v[i]-oldAngle1v)
@inbounds dAngle2 = Vector3(0.5,0.5,0.5) *(E_angle2v[i]-oldAngle2v)
@inbounds strain=(E_pos2[i].x/E_currentRestLength[i])
positiveEnd=true
if axialStrain( positiveEnd,strain)>100.0
diverged=true
@cuprintln("DIVERGED!!!!!!!!!!")
return
end
@inbounds E = E_stiffness[i]
@inbounds l = E_currentRestLength[i]
nu=0
# L = 5.0 #?? change!!!!!!
L=l
a1 = E*L # EA/L : Units of N/m
a2 = E * L*L*L / (12.0*(1+nu)) # GJ/L : Units of N-m
b1 = E*L # 12EI/L^3 : Units of N/m
b2 = E*L*L/2.0 # 6EI/L^2 : Units of N (or N-m/m: torque related to linear distance)
b3 = E*L*L*L/6.0 # 2EI/L : Units of N-m
nu=0.35
W = 75
# L = W/sqrt(2)
l=L
n_min = 1
n_max = 7
# Cross Section inputs, must be floats
mass=125000 #before for voxel
mass=10
E = 2000 # MPa
G = E * 1 / 3 # MPa
h = 2.38 # mm
b = 2.38 # mm
rho = 7.85e-9 / 3 # kg/mm^3
S = h * b
Sy = (S * (6 + 12 * nu + 6 * nu^2)/ (7 + 12 * nu + 4 * nu^2))
# For solid rectangular cross section (width=b, depth=d & ( b < d )):
Q = 1 / 3 - 0.2244 / (min(h / b, b / h) + 0.1607)
Jxx = Q * min(h * b^3, b * h^3)
s=b
MaxFreq2=E*s/mass
dt= 1/(6.283185*sqrt(MaxFreq2))
##if voxels
#nu=0
#L=l
#a1 = E*L # EA/L : Units of N/m
#a2 = E * L*L*L / (12.0*(1+nu)) # GJ/L : Units of N-m
#b1 = E*L # 12EI/L^3 : Units of N/m
#b2 = E*L*L/2.0 # 6EI/L^2 : Units of N (or N-m/m: torque related to linear distance)
#b3 = E*L*L*L/6.0 # 2EI/L : Units of N-m
I= b*h^3/12
J=b*h*(b*b+h*h)/12
a1=E*b*h/L
a2=G*J/L
b1=12*E*I/(L^3)
b2=6*E*I/(L^2)
b3=2*E*I/(L)
#inbounds currentTransverseArea=25.0 #?? change!!!!!! E_area[i]
@inbounds currentTransverseArea= b*h
@inbounds _stress=updateStrain(strain,E)
#@inbounds currentTransverseArea= E_area[i]
#@inbounds _stress=updateStrain(strain,E_stiffness[i])
@inbounds E_stress[i]=_stress
#@cuprintln("_stress $_stress")
x=(_stress*currentTransverseArea)
@inbounds y=(b1*E_pos2[i].y-b2*(E_angle1v[i].z + E_angle2v[i].z))
@inbounds z=(b1*E_pos2[i].z + b2*(E_angle1v[i].y + E_angle2v[i].y))
x=convert(Float64,x)
y=convert(Float64,y)
z=convert(Float64,z)
# Use Curstress instead of -a1*Pos2.x to account for non-linear deformation
forceNeg = Vector3(x,y,z)
forcePos = Vector3(-x,-y,-z)
@inbounds x= (a2*(E_angle2v[i].x-E_angle1v[i].x))
@inbounds y= (-b2*E_pos2[i].z-b3*(2.0*E_angle1v[i].y+E_angle2v[i].y))
@inbounds z=(b2*E_pos2[i].y - b3*(2.0*E_angle1v[i].z + E_angle2v[i].z))
x=convert(Float64,x)
y=convert(Float64,y)
z=convert(Float64,z)
momentNeg = Vector3(x,y,z)
@inbounds x= (a2*(E_angle1v[i].x-E_angle2v[i].x))
@inbounds y= (-b2*E_pos2[i].z- b3*(E_angle1v[i].y+2.0*E_angle2v[i].y))
@inbounds z=(b2*E_pos2[i].y - b3*(E_angle1v[i].z + 2.0*E_angle2v[i].z))
x=convert(Float64,x)
y=convert(Float64,y)
z=convert(Float64,z)
momentPos = Vector3(x,y,z)
### damping
@inbounds if E_damp[i] #first pass no damping
sqA1=CUDAnative.sqrt(a1)
sqA2xIp=CUDAnative.sqrt(a2*L*L/6.0)
sqB1=CUDAnative.sqrt(b1)
sqB2xFMp=CUDAnative.sqrt(b2*L/2)
sqB3xIp=CUDAnative.sqrt(b3*L*L/6.0)
dampingMultiplier=Vector3(28099.3,28099.3,28099.3) # 2*mat->_sqrtMass*mat->zetaInternal/previousDt;?? todo link to material
zeta=1
dampingM= 2*sqrt(mass)*zeta/dt
dampingMultiplier=Vector3(dampingM,dampingM,dampingM)
posCalc=Vector3(sqA1*dPos2.x, sqB1*dPos2.y - sqB2xFMp*(dAngle1.z+dAngle2.z),sqB1*dPos2.z + sqB2xFMp*(dAngle1.y+dAngle2.y))
forceNeg =forceNeg + (dampingMultiplier*posCalc);
forcePos =forcePos - (dampingMultiplier*posCalc);
momentNeg -= Vector3(0.5,0.5,0.5)*dampingMultiplier*Vector3(-sqA2xIp*(dAngle2.x - dAngle1.x),
sqB2xFMp*dPos2.z + sqB3xIp*(2*dAngle1.y + dAngle2.y),
-sqB2xFMp*dPos2.y + sqB3xIp*(2*dAngle1.z + dAngle2.z));
momentPos -= Vector3(0.5,0.5,0.5)*dampingMultiplier*Vector3(sqA2xIp*(dAngle2.x - dAngle1.x),
sqB2xFMp*dPos2.z + sqB3xIp*(dAngle1.y + 2*dAngle2.y),
-sqB2xFMp*dPos2.y + sqB3xIp*(dAngle1.z + 2*dAngle2.z));
else
@inbounds E_damp[i]=true
end
smallAngle=true
if !smallAngle # ?? check
@inbounds forceNeg = RotateVec3DInv(E_angle1[i],forceNeg)
@inbounds momentNeg = RotateVec3DInv(E_angle1[i],momentNeg)
end
@inbounds forcePos = RotateVec3DInv(E_angle2[i],forcePos)
@inbounds momentPos = RotateVec3DInv(E_angle2[i],momentPos)
@inbounds forceNeg =toAxisOriginalVector3(forceNeg,E_axis[i])
@inbounds forcePos =toAxisOriginalVector3(forcePos,E_axis[i])
@inbounds momentNeg=toAxisOriginalQuat(momentNeg,E_axis[i])# TODOO CHECKKKKKK
@inbounds momentPos=toAxisOriginalQuat(momentPos,E_axis[i])
@inbounds E_intForce1[i] =forceNeg
@inbounds E_intForce2[i] =forcePos
@inbounds x= momentNeg.x
@inbounds y= momentNeg.y
@inbounds z= momentNeg.z
x=convert(Float64,x)
y=convert(Float64,y)
z=convert(Float64,z)
@inbounds E_intMoment1[i]=Vector3(x,y,z)
@inbounds x= momentNeg.x
@inbounds y= momentNeg.y
@inbounds z= momentNeg.z
x=convert(Float64,x)
y=convert(Float64,y)
z=convert(Float64,z)
@inbounds E_intMoment2[i]=Vector3(x,y,z)
#x=E_pos2[i].x*10000000000
#y=E_pos2[i].y*10000000000
#z=E_pos2[i].z*10000000000
#@cuprintln("pos2 x $x, y $y, z $z ")
##x=E_intMoment2[i].x*10000000000
#y=E_intMoment2[i].y*10000000000
#z=E_intMoment2[i].z*10000000000
#@cuprintln("E_intMoment2 x $x, y $y, z $z ")
end
return
end
function run_updateEdges!(E_source,E_target,E_area,E_density,E_stiffness,E_stress,E_axis,E_currentRestLength,E_pos2,E_angle1v,E_angle2v,E_angle1,E_angle2,E_intForce1,E_intMoment1,E_intForce2,E_intMoment2,E_damp,N_currPosition,N_orient)
N=length(E_source)
numblocks = ceil(Int, N/256)
CuArrays.@sync begin
@cuda threads=256 blocks=numblocks updateEdges!(E_source,E_target,E_area,E_density,
E_stiffness,E_stress,E_axis,E_currentRestLength,E_pos2,E_angle1v,
E_angle2v,E_angle1,E_angle2,E_intForce1,E_intMoment1,E_intForce2,
E_intMoment2,E_damp,N_currPosition,N_orient)
end
end
#####################################################
function floorPenetration(y)
nomSize=0.001
floor=-25
m=0.0
if(y-floor<0.0)
m=(-(y-floor))
end
return m
end
#Returns the interference (in meters) between the collision envelope of this voxel and the floor at Z=0. Positive numbers correspond to interference. If the voxel is not touching the floor 0 is returned.
function penetrationStiffness()
E=2000.0
nomSize=0.001
mass=10
massInverse=1.0/mass #
return (2.0*E*nomSize)
end
#!< returns the stiffness with which this voxel will resist penetration. This is calculated according to E*A/L with L = voxelSize/2.
function collisionDampingTranslateC()
E=2000.0
nomSize=0.001
mass=10
massInverse=1.0/mass #
_2xSqMxExS = (2.0*CUDAnative.sqrt(mass*E*nomSize));
zetaCollision=0.5;
return zetaCollision*_2xSqMxExS;
end #!< Returns the global material damping coefficient (translation)
function floorForce!(dt,pTotalForce,y ,linMom,FloorStaticFriction)
E=2000.0
nomSize=0.001
mass=10
massInverse=1.0/mass #
CurPenetration = floorPenetration(convert(Float64,y)); #for now use the average.
muStatic=0.2 ;
muKinetic=0.01; #normal force = 1e3*0.001
if (CurPenetration>=0.0)
vel = linMom*Vector3((massInverse),(massInverse),(massInverse)) #Returns the 3D velocity of this voxel in m/s (GCS)
horizontalVel= Vector3(convert(Float64,vel.x), 0.0, convert(Float64,vel.z));
normalForce = 2.0*E*nomSize*CurPenetration;
pTotalForce=Vector3( pTotalForce.x, convert(Float64,pTotalForce.y) + normalForce - collisionDampingTranslateC()*convert(Float64,vel.y),pTotalForce.z)
#in the z direction: k*x-C*v - spring and damping
if (FloorStaticFriction) #If this voxel is currently in static friction mode (no lateral motion)
# assert(horizontalVel.Length2() == 0);
surfaceForceSq = convert(Float64,(pTotalForce.x*pTotalForce.x + pTotalForce.z*pTotalForce.z)); #use squares to avoid a square root
frictionForceSq = (muStatic*normalForce)*(muStatic*normalForce);
if (surfaceForceSq > frictionForceSq)
FloorStaticFriction=false; #if we're breaking static friction, leave the forces as they currently have been calculated to initiate motion this time step
end
else #even if we just transitioned don't process here or else with a complete lack of momentum it'll just go back to static friction
#add a friction force opposing velocity according to the normal force and the kinetic coefficient of friction
leng=CUDAnative.sqrt((convert(Float64,vel.x) * convert(Float64,vel.x)) + (0.0 * 0.0) + (convert(Float64,vel.z) * convert(Float64,vel.z)))
horizontalVel= Vector3(convert(Float64,vel.x)/(leng+0.00000000001),0.0,convert(Float64,vel.z)/(leng+0.00000000001))
pTotalForce = pTotalForce- Vector3(muKinetic*normalForce,muKinetic*normalForce,muKinetic*normalForce) * horizontalVel;
end
else
FloorStaticFriction=false;
end
return pTotalForce,FloorStaticFriction
end
#####################################################
function updateNodes!(dt,currentTimeStep,N_position, N_restrained,N_displacement,N_angle,N_currPosition,N_linMom,N_angMom,N_intForce,N_intMoment,N_force,N_moment,N_orient,N_edgeID,N_edgeFirst,E_intForce1,E_intMoment1,E_intForce2,E_intMoment2)
index = (blockIdx().x - 1) * blockDim().x + threadIdx().x
stride = blockDim().x * gridDim().x
## @cuprintln("thread $index, block $stride")
N,M=size(N_edgeID)
for i = index:stride:N
if false
# @inbounds if N_restrained[i]
return
else
for j in 1:M
temp=N_edgeID[i,j]
@inbounds if (N_edgeID[i,j]!=-1)
#@cuprintln("i $i, j $j, N_edgeID[i,j] $temp")
@inbounds N_intForce[i]=ifelse(N_edgeFirst[i,j], N_intForce[i]+E_intForce1[N_edgeID[i,j]], N_intForce[i]+E_intForce2[N_edgeID[i,j]] )
@inbounds N_intMoment[i]=ifelse(N_edgeFirst[i,j], N_intMoment[i]+E_intMoment1[N_edgeID[i,j]], N_intMoment[i]+E_intMoment2[N_edgeID[i,j]] )
end
end
@inbounds curForce = force(N_intForce[i],N_orient[i],N_force[i],true,currentTimeStep)
gravity=true;
isFloorEnabled=true;
static=false;
FloorStaticFriction=false;
E=2000.0
nomSize=0.001
mass=10
massInverse=1.0/mass #
grav=-mass*9.80665*0.1;
if(gravity && !static)
curForce =curForce +Vector3(0,grav,0);
end
fricForce = Vector3(curForce.x,curForce.y,curForce.z);
if (isFloorEnabled)
@inbounds curForce,FloorStaticFriction=floorForce!(dt,curForce,N_currPosition[i].y,Vector3(N_linMom[i].x,N_linMom[i].y ,N_linMom[i].z),FloorStaticFriction)
end
fricForce = curForce-fricForce;
#########################################
@inbounds N_intForce[i]=Vector3(0,0,0)
@inbounds N_linMom[i]=N_linMom[i]+curForce*Vector3(dt,dt,dt) #todo make sure right
@inbounds translate=N_linMom[i]*Vector3((dt*massInverse),(dt*massInverse),(dt*massInverse)) # ??massInverse
############################
#we need to check for friction conditions here (after calculating the translation) and stop things accordingly
@inbounds if (isFloorEnabled && floorPenetration( N_currPosition[i].y)>= 0.0 && !static)#we must catch a slowing voxel here since it all boils down to needing access to the dt of this timestep.
work =convert(Float64,fricForce.x*translate.x + fricForce.z*translate.z); #F dot disp
hKe = 0.5*massInverse*convert(Float64,(N_linMom[i].x*N_linMom[i].x + N_linMom[i].z*N_linMom[i].z)); #horizontal kinetic energy
if((hKe + work) <= 0.0)
FloorStaticFriction=true; #this checks for a change of direction according to the work-energy principle
end
if(FloorStaticFriction)
#if we're in a state of static friction, zero out all horizontal motion
N_linMom[i]=Vector3(0.0 ,convert(Float64,N_linMom[i].y) ,0.0)
translate=Vector3(0.0 ,convert(Float64,translate.y) ,0.0)
end
else
FloorStaticFriction=false
end
#x=translate.x*10000000000
#y=translate.y*10000000000
#z=translate.z*10000000000
#@cuprintln("translate x $x, y $y, z $z ")
@inbounds N_currPosition[i]=N_currPosition[i]+translate
@inbounds N_displacement[i]=N_displacement[i]+translate
# Rotation
@inbounds curMoment = moment(N_intMoment[i],N_orient[i],N_moment[i])
@inbounds N_intMoment[i]=Vector3(0,0,0) # do i really need it?
@inbounds N_angMom[i]=N_angMom[i]+curMoment*Vector3(dt,dt,dt)
momentInertiaInverse=1.92e-6 # todo ?? later change 1/Inertia (1/(kg*m^2))
@inbounds temp=FromRotationVector(N_angMom[i]*Vector3((dt*momentInertiaInverse),(dt*momentInertiaInverse),(dt*momentInertiaInverse)))
#x=temp.x*10000000000
#y=temp.y*10000000000
#z=temp.z*10000000000
#@cuprintln("temp x $x, y $y, z $z ")
@inbounds N_orient[i]=multiplyQuaternions(temp,N_orient[i])
#@inbounds x= N_orient[i].x*temp.x
#@inbounds y= N_orient[i].y*temp.y
#@inbounds z= N_orient[i].z*temp.z
#@inbounds w= N_orient[i].w*temp.w
#x=convert(Float64,x)
#y=convert(Float64,y)
#z=convert(Float64,z)
#w=convert(Float64,w)
#@inbounds N_orient[i]=Quaternion(x,y,z,w)
#x=N_orient[i].x*10000000000
#y=N_orient[i].y*10000000000
#z=N_orient[i].z*10000000000
#w=N_orient[i].w
#@cuprintln("N_orient x $x, y $y, z $z, w $w ")
end
end
return
end
function run_updateNodes!(dt,currentTimeStep,N_position, N_restrained,N_displacement, N_angle,N_currPosition,N_linMom,N_angMom,N_intForce,N_intMoment,N_force,N_moment,N_orient,N_edgeID,N_edgeFirst,E_intForce1,E_intMoment1,E_intForce2,E_intMoment2)
N=length(N_intForce)
numblocks = ceil(Int, N/256)
CuArrays.@sync begin
@cuda threads=256 blocks=numblocks updateNodes!(dt,currentTimeStep,N_position, N_restrained,N_displacement, N_angle,N_currPosition,N_linMom,N_angMom,N_intForce,N_intMoment,N_force,N_moment,N_orient,N_edgeID,N_edgeFirst,E_intForce1,E_intMoment1,E_intForce2,E_intMoment2)
end
end
#####################################################
function orientLink!(currentRestLength,pVNeg,pVPos,oVNeg,oVPos,axis) # updates pos2, angle1, angle2, and smallAngle //Quat3D<double> /*double restLength*/
pos2 = toAxisXVector3(pVPos-pVNeg,axis) # digit truncation happens here...
angle1 = toAxisXQuat(oVNeg,axis)
angle2 = toAxisXQuat(oVPos,axis)
totalRot = conjugate(angle1) #keep track of the total rotation of this bond (after toAxisX()) # Quat3D<double>
pos2 = RotateVec3D(totalRot,pos2)
#x=pos2.x*10000000000
#y=pos2.y*10000000000
#z=pos2.z*10000000000
#@cuprintln("pos2 2 x $x, y $y, z $z ")
#x=totalRot.x*10000000000
#y=totalRot.y*10000000000
#z=totalRot.z*10000000000
#@cuprintln("totalRot x $x, y $y, z $z ")
# x=pos2.x*10000000000
# y=pos2.y*10000000000
# z=pos2.z*10000000000
# @cuprintln("pos2 x $x, y $y, z $z ")
angle2 = Quaternion(angle2.x*totalRot.x,angle2.y*totalRot.y,angle2.z*totalRot.z,angle2.w*totalRot.w)
angle1 = Quaternion(0.0,0.0,0.0,1.0)#new THREE.Quaternion() #zero for now...
smallAngle=true #todo later remove
if (smallAngle) #Align so Angle1 is all zeros
#pos2[1] =pos2[1]- currentRestLength #only valid for small angles
pos2=Vector3(pos2.x-currentRestLength,pos2.y,pos2.z)
else #Large angle. Align so that Pos2.y, Pos2.z are zero.
# FromAngleToPosX(angle1,pos2) #get the angle to align Pos2 with the X axis
# totalRot = angle1.clone().multiply(totalRot) #update our total rotation to reflect this
# angle2 = angle1.clone().multiply( angle2) #rotate angle2
# pos2 = new THREE.Vector3(pos2.length() - currentRestLength, 0, 0);
end
angle1v = ToRotationVector(angle1)
angle2v = ToRotationVector(angle2)
# pos2,angle1v,angle2v,angle1,angle2,
return pos2,angle1v,angle2v,angle1,angle2,totalRot
end
#####################################################
function toAxisXVector3(pV::Vector3,axis::Vector3) #TODO CHANGE
xaxis=Vector3(1.0,0.0,0.0)
vector=normalizeVector3(axis)
q=setFromUnitVectors(vector,xaxis)
v=applyQuaternion1( pV ,q )
return Vector3(v.x,v.y,v.z)
end
function toAxisOriginalVector3(pV::Vector3,axis::Vector3)
xaxis=Vector3(1.0,0.0,0.0)
vector=normalizeVector3(axis)
q=setFromUnitVectors(xaxis,vector)
v=applyQuaternion1( pV ,q )
return Vector3(v.x,v.y,v.z)
end
function toAxisXQuat(pQ::Quaternion,axis::Vector3)
xaxis=Vector3(1.0,0.0,0.0)
vector=normalizeVector3(axis)
q=setFromUnitVectors(vector,xaxis)
pV=Vector3(pQ.x,pQ.y,pQ.z)
v=applyQuaternion1( pV ,q )
return Quaternion(v.x,v.y,v.z,1.0)
end
function toAxisOriginalQuat(pQ::Vector3,axis::Vector3)
xaxis=Vector3(1.0,0.0,0.0)
vector=normalizeVector3(axis)
q=setFromUnitVectors(xaxis,vector)
pV=Vector3(pQ.x,pQ.y,pQ.z)
v=applyQuaternion1( pV ,q )
return Quaternion(v.x,v.y,v.z,1.0)
end
#####################################################
function setFromUnitVectors(vFrom::Vector3, vTo::Vector3)
# assumes direction vectors vFrom and vTo are normalized
EPS = 0.000000001;
r= dotVector3(vFrom,vTo)+1.0
# r = dot(vFrom,vTo)+1
if r < EPS
r = 0;
if abs( vFrom.x ) > abs( vFrom.z )
qx = - vFrom.y
qy = vFrom.x
qz = 0.0
qw = r
else
qx = 0.0
qy = -(vFrom.z)
qz = vFrom.y
qw = r
end
else
# crossVectors( vFrom, vTo ); // inlined to avoid cyclic dependency on Vector3
qx = vFrom.y * vTo.z - vFrom.z * vTo.y
qy = vFrom.z * vTo.x - vFrom.x * vTo.z
qz = vFrom.x * vTo.y - vFrom.y * vTo.x
qw = r
end
qx= (qx==-0.0) ? 0.0 : qx
qy= (qy==-0.0) ? 0.0 : qy
qz= (qz==-0.0) ? 0.0 : qz
qw= (qw==-0.0) ? 0.0 : qw
mx=qx*qx
my=qy*qy
mz=qz*qz
mw=qw*qw
mm=mx+my
mm=mm+mz
mm=mm+mw
mm=convert(Float64,mm)#??????????????????? todo check later
l=CUDAnative.sqrt(mm)
#l = sqrt((qx * qx) + (qy * qy) + (qz * qz)+ (qw * qw))
if l === 0
qx = 0.0
qy = 0.0
qz = 0.0
qw = 1.0
else
l = 1.0 / l
qx = qx * l
qy = qy * l
qz = qz * l
qw = qw * l
end
# return qx,qy,qz,qw
return Quaternion(qx,qy,qz,qw)
# return normalizeQ(Quat(qw,qx,qy,qz))
# return Quat(nn[1], nn[2], nn[3], nn[4])
end
function quatToMatrix( quaternion::Quaternion)
#te = RotationMatrix()
x = quaternion.x
y = quaternion.y
z = quaternion.z
w = quaternion.w
x2 = x + x
y2 = y + y
z2 = z + z
xx = x * x2
xy = x * y2
xz = x * z2
yy = y * y2
yz = y * z2
zz = z * z2
wx = w * x2
wy = w * y2
wz = w * z2
sx = 1.0
sy = 1.0
sz = 1.0
te1 = ( 1.0 - ( yy + zz ) ) * sx
te2 = ( xy + wz ) * sx
te3 = ( xz - wy ) * sx
te4 = 0.0
te5 = ( xy - wz ) * sy
te6 = ( 1.0 - ( xx + zz ) ) * sy
te7 = ( yz + wx ) * sy
te8 = 0.0
te9 = ( xz + wy ) * sz
te10 = ( yz - wx ) * sz
te11 = ( 1.0 - ( xx + yy ) ) * sz
te12 = 0.0
te13 = 0.0 #position.x;
te14 = 0.0 #position.y;
te15 = 0.0 #position.z;
te16 = 1.0
te= RotationMatrix(te1,te2,te3,te4,te5,te6,te7,te8,te9,te10,te11,te12,te13,te14,te15,te16)
return te
end
function setFromRotationMatrix(m::RotationMatrix)
m11 = convert(Float64,m.te1 )
m12 = convert(Float64,m.te5 )
m13 = convert(Float64,m.te9 )
m21 = convert(Float64,m.te2 )
m22 = convert(Float64,m.te6 )
m23 = convert(Float64,m.te10)
m31 = convert(Float64,m.te3 )
m32 = convert(Float64,m.te7 )
m33 = convert(Float64,m.te11)
y = CUDAnative.asin( clamp( m13, -1.0, 1.0 ) ) ##check if has to be changed to cuda
if ( abs( m13 ) < 0.9999999999 )
x = CUDAnative.atan2( - m23, m33 )
z = CUDAnative.atan2( - m12, m11 )#-m12, m11
else
x = CUDAnative.atan2( m32, m22 )
z = 0.0;
end
return Vector3(x,y,z)
end
function setQuaternionFromEuler(euler::Vector3)
x=euler.x
y=euler.y
z=euler.z
c1 = CUDAnative.cos( x / 2.0 )
c2 = CUDAnative.cos( y / 2.0 )
c3 = CUDAnative.cos( z / 2.0 )
s1 = CUDAnative.sin( x / 2.0 )
s2 = CUDAnative.sin( y / 2.0 )
s3 = CUDAnative.sin( z / 2.0 )
x = s1 * c2 * c3 + c1 * s2 * s3
y = c1 * s2 * c3 - s1 * c2 * s3
z = c1 * c2 * s3 + s1 * s2 * c3
w = c1 * c2 * c3 - s1 * s2 * s3
return Quaternion(x,y,z,w)
end
function applyQuaternion1(e::Vector3,q2::Quaternion)
x = e.x
y = e.y
z = e.z
qx = q2.x
qy = q2.y
qz = q2.z
qw = q2.w
# calculate quat * vector
ix = qw * x + qy * z - qz * y
iy = qw * y + qz * x - qx * z
iz = qw * z + qx * y - qy * x
iw = - qx * x - qy * y - qz * z
# calculate result * inverse quat
xx = ix * qw + iw * - qx + iy * - qz - iz * - qy
yy = iy * qw + iw * - qy + iz * - qx - ix * - qz
zz = iz * qw + iw * - qz + ix * - qy - iy * - qx
d=15
return Vector3(xx,yy,zz)
end
#####################################################
function conjugate(q::Quaternion)
x= (-q.x==-0) ? 0.0 : -q.x
y= (-q.y==-0) ? 0.0 : -q.y
z= (-q.z==-0) ? 0.0 : -q.z
w=q.w
x=convert(Float64,x)
y=convert(Float64,y)
z=convert(Float64,z)
w=convert(Float64,w)
return Quaternion(x,y,z,w)
end
function RotateVec3D(a::Quaternion, f::Vector3)
fx= (f.x==-0) ? 0 : f.x
fy= (f.y==-0) ? 0 : f.y
fz= (f.z==-0) ? 0 : f.z
# fx= f.x
# fy= f.y
# fz= f.z
tw = fx*a.x + fy*a.y + fz*a.z
tx = fx*a.w - fy*a.z + fz*a.y
ty = fx*a.z + fy*a.w - fz*a.x
tz = -fx*a.y + fy*a.x + fz*a.w
return Vector3((a.w*tx+a.x*tw+a.y*tz-a.z*ty),(a.w*ty-a.x*tz+a.y*tw+a.z*tx),(a.w*tz+a.x*ty-a.y*tx+a.z*tw))
end
#!< Returns a vector representing the specified vector "f" rotated by this quaternion. @param[in] f The vector to transform.
function RotateVec3DInv(a::Quaternion, f::Vector3)
fx=f.x
fy=f.y
fz=f.z
tw = a.x*fx + a.y*fy + a.z*fz
tx = a.w*fx - a.y*fz + a.z*fy
ty = a.w*fy + a.x*fz - a.z*fx
tz = a.w*fz - a.x*fy + a.y*fx
return Vector3((tw*a.x + tx*a.w + ty*a.z - tz*a.y),(tw*a.y - tx*a.z + ty*a.w + tz*a.x),(tw*a.z + tx*a.y - ty*a.x + tz*a.w))
end
#!< Returns a vector representing the specified vector "f" rotated by the inverse of this quaternion. This is the opposite of RotateVec3D. @param[in] f The vector to transform.
function ToRotationVector(a::Quaternion)
if (a.w >= 1.0 || a.w <= -1.0)
return Vector3(0.0,0.0,0.0)
end
squareLength = 1.0-a.w*a.w; # because x*x + y*y + z*z + w*w = 1.0, but more susceptible to w noise (when
SLTHRESH_ACOS2SQRT= 2.4e-3; # SquareLength threshhold for when we can use square root optimization for acos. From SquareLength = 1-w*w. (calculate according to 1.0-W_THRESH_ACOS2SQRT*W_THRESH_ACOS2SQRT
if (squareLength < SLTHRESH_ACOS2SQRT) # ???????
x=a.x*(2.0*CUDAnative.sqrt((2-2*a.w)/squareLength))
y=a.y*(2.0*CUDAnative.sqrt((2-2*a.w)/squareLength))
z=a.z*(2.0*CUDAnative.sqrt((2-2*a.w)/squareLength))
x=convert(Float64,x)
y=convert(Float64,y)
z=convert(Float64,z)
return Vector3(x,y,z) ; # acos(w) = sqrt(2*(1-x)) for w close to 1. for w=0.001, error is 1.317e-6
else
x=a.x*(2.0*CUDAnative.acos(a.w)/CUDAnative.sqrt(squareLength))
y=a.y*(2.0*CUDAnative.acos(a.w)/CUDAnative.sqrt(squareLength))
z=a.z*(2.0*CUDAnative.acos(a.w)/CUDAnative.sqrt(squareLength))
x=convert(Float64,x)
y=convert(Float64,y)
z=convert(Float64,z)
return Vector3(x,y,z)
end
end
# !< Returns a rotation vector representing this quaternion rotation. Adapted from http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/
function FromRotationVector(VecIn::Vector3)
theta=VecIn*Vector3(0.5,0.5,0.5)
ntheta=CUDAnative.sqrt((theta.x * theta.x) + (theta.y * theta.y) + (theta.z * theta.z))
thetaMag2=ntheta*ntheta
DBL_EPSILONx24 =5.328e-15
if thetaMag2*thetaMag2 < DBL_EPSILONx24
qw=1.0 - 0.5*thetaMag2
s=1.0 - thetaMag2 / 6.0
else
thetaMag = CUDAnative.sqrt(thetaMag2)
qw=CUDAnative.cos(thetaMag)
s=CUDAnative.sin(thetaMag) / thetaMag
end
qx=theta.x*s
qy=theta.y*s
qz=theta.z*s
qx=convert(Float64,qx)
qy=convert(Float64,qy)
qz=convert(Float64,qz)
qw=convert(Float64,qw)
return Quaternion(qx,qy,qz,qw)
end
function multiplyQuaternions(q::Quaternion,f::Quaternion)
x=q.x
y=q.y
z=q.z
w=q.w
x1=w*f.x + x*f.w + y*f.z - z*f.y
y1=w*f.y - x*f.z + y*f.w + z*f.x
z1=w*f.z + x*f.y - y*f.x + z*f.w
w1=w*f.w - x*f.x - y*f.y - z*f.z
return Quaternion(x1,y1,z1,w1 ); #!< overload quaternion multiplication.
end
#####################################################
function updateStrain( axialStrain,E) # ?from where strain
strain = axialStrain # redundant?
currentTransverseStrainSum=0.0 # ??? todo
linear=true
maxStrain=1000000000000000;# ?? todo later change
if linear
if axialStrain > maxStrain
maxStrain = axialStrain # remember this maximum for easy reference
end
return stress(axialStrain,E)
else
if (axialStrain > maxStrain) # if new territory on the stress/strain curve
maxStrain = axialStrain # remember this maximum for easy reference
returnStress = stress(axialStrain,E) # ??currentTransverseStrainSum
if (nu != 0.0)
strainOffset = maxStrain-stress(axialStrain,E)/(_eHat*(1.0-nu)) # precalculate strain offset for when we back off
else
strainOffset = maxStrain-returnStress/E # precalculate strain offset for when we back off
end
else # backed off a non-linear material, therefore in linear region.
relativeStrain = axialStrain-strainOffset # treat the material as linear with a strain offset according to the maximum plastic deformation
if (nu != 0.0)
returnStress = stress(relativeStrain,E)
else
returnStress = E*relativeStrain
end
end
return returnStress
end
end
function stress( strain , E ) #end,transverseStrainSum, forceLinear){
# reference: http://www.colorado.edu/engineering/CAS/courses.d/Structures.d/IAST.Lect05.d/IAST.Lect05.pdf page 10
# if (isFailed(strain)) return 0.0f; //if a failure point is set and exceeded, we've broken!
# var E =setup.edges[0].stiffness; //todo change later to material ??
# var E=1000000;//todo change later to material ??
# var scaleFactor=1;
return E*strain;
# # if (strain <= strainData[1] || linear || forceLinear){ //for compression/first segment and linear materials (forced or otherwise), simple calculation
# if (nu==0.0) return E*strain;
# else return _eHat*((1-nu)*strain + nu*transverseStrainSum);
# else return eHat()*((1-nu)*strain + nu*transverseStrainSum);
# # }
#//the non-linear feature with non-zero poissons ratio is currently experimental
#int DataCount = modelDataPoints();
#for (int i=2; i<DataCount; i++){ //go through each segment in the material model (skipping the first segment because it has already been handled.
# if (strain <= strainData[i] || i==DataCount-1){ //if in the segment ending with this point (or if this is the last point extrapolate out)
# float Perc = (strain-strainData[i-1])/(strainData[i]-strainData[i-1]);
# float basicStress = stressData[i-1] + Perc*(stressData[i]-stressData[i-1]);
# if (nu==0.0f) return basicStress;
# else { //accounting for volumetric effects
# float modulus = (stressData[i]-stressData[i-1])/(strainData[i]-strainData[i-1]);
# float modulusHat = modulus/((1-2*nu)*(1+nu));
# float effectiveStrain = basicStress/modulus; //this is the strain at which a simple linear stress strain line would hit this point at the definied modulus
# float effectiveTransverseStrainSum = transverseStrainSum*(effectiveStrain/strain);
# return modulusHat*((1-nu)*effectiveStrain + nu*effectiveTransverseStrainSum);
# }
# }
#}
# assert(false); //should never reach this point
# return 0.0f;
end
function axialStrain( positiveEnd,strain)
#strainRatio = pVPos->material()->E/pVNeg->material()->E;
strainRatio=1.0;
return positiveEnd ? 2.0 *strain*strainRatio/(1.0+strainRatio) : 2.0*strain/(1.0+strainRatio)
end
#####################################################
function force(N_intForce,N_orient,N_force,static,currentTimeStep)
# forces from internal bonds
totalForce=Vector3(0,0,0)
# new THREE.Vector3(node.force.x,node.force.y,node.force.z);
# todo
totalForce=totalForce+N_intForce
# for (int i=0; i<6; i++){
# if (links[i]) totalForce += links[i]->force(isNegative((linkDirection)i)); # total force in LCS
# }
totalForce = RotateVec3D(N_orient,totalForce); # from local to global coordinates
# assert(!(totalForce.x != totalForce.x) || !(totalForce.y != totalForce.y) || !(totalForce.z != totalForce.z)); //assert non QNAN
# other forces
if(static)
totalForce=totalForce+N_force
# }else if(currentTimeStep<50){
# totalForce.add(new THREE.Vector3(node.force.x,node.force.y,node.force.z));
else
# var ex=0.1;
# if(node.force.y!=0){
# var f=400*Math.sin(currentTimeStep*ex);
# totalForce.add(new THREE.Vector3(0,f,0));
# }
#x=N_position[node][3]
#t=currentTimeStep
#wave=getForce(x,t)
#totalForce=totalForce+[0 wave 0]
end
# if (externalExists()) totalForce += external()->force(); //external forces
# totalForce -= velocity()*mat->globalDampingTranslateC(); //global damping f-cv
# totalForce.z += mat->gravityForce(); //gravity, according to f=mg
# if (isCollisionsEnabled()){
# for (std::vector<CVX_Collision*>::iterator it=colWatch->begin(); it!=colWatch->end(); it++){
# totalForce -= (*it)->contactForce(this);
# }
# }
# todo make internal forces 0 again
# N_intForce[node]=[0 0 0] # do i really need it?
# node.force.x=0;
# node.force.y=0;
# node.force.z=0;
return totalForce
end
function moment(intMoment,orient,moment)
#moments from internal bonds
totalMoment=Vector3(0,0,0)
# for (int i=0; i<6; i++){
# if (links[i]) totalMoment += links[i]->moment(isNegative((linkDirection)i)); //total force in LCS
# }
totalMoment=totalMoment+intMoment
totalMoment = RotateVec3D(orient,totalMoment);
totalMoment=totalMoment+moment
#other moments
# if (externalExists()) totalMoment += external()->moment(); //external moments
# totalMoment -= angularVelocity()*mat->globalDampingRotateC(); //global damping
return totalMoment
end
#####################################################
function updateDataAndSave!(metavoxel,setup,fileName,displacements)
nodes = setup["nodes"]
edges = setup["edges"]
setup["animation"]["showDisplacement"]=true
voxCount=size(nodes)[1]
linkCount=size(edges)[1]
N_displacement=Array(metavoxel["N_displacementGPU"])
N_angle=Array(metavoxel["N_angleGPU"])
E_stress=Array(metavoxel["E_stressGPU"])
setup["viz"]["maxStress"]=maximum(E_stress)
setup["viz"]["minStress"]=minimum(E_stress)
i=1
for edge in edges
edge["stress"]=E_stress[i]
i=i+1
end
i=1
for node in nodes
node["posTimeSteps"]=[]
node["angTimeSteps"]=[]
node["displacement"]["x"]=N_displacement[i].x/15
node["displacement"]["y"]=N_displacement[i].y/15
node["displacement"]["z"]=N_displacement[i].z/15
node["angle"]["x"]=N_angle[i].x
node["angle"]["y"]=N_angle[i].y
node["angle"]["z"]=N_angle[i].z
i=i+1
end
for j in 1:length(displacements)
i=1
for node in nodes
d=displacements[j][i]
dis = Dict{String, Float64}("x" => d.x/15, "y" => d.y/15,"z" => d.z/15)
append!(node["posTimeSteps"],[dis])
ang = Dict{String, Float64}("x" => N_angle[i].x, "y" => N_angle[i].y,"z" => N_angle[i].z)
append!(node["angTimeSteps"],[ang])
i=i+1
end
end
# pass data as a json string (how it shall be displayed in a file)
stringdata = JSON.json(setup)
# write the file with the stringdata variable information
open(fileName, "w") do f
write(f, stringdata)
end
end
#####################################################
function runMetavoxelGPU!(setup,numTimeSteps,latticeSize,displacements,returnEvery,save)
function initialize!(setup)
nodes = setup["nodes"]
edges = setup["edges"]
i=1
# pre-calculate current position
for node in nodes
# element=parse(Int,node["id"][2:end])
N_position[i]=Vector3(node["position"]["x"]*15.0,node["position"]["y"]*15.0,node["position"]["z"]*15.0)
N_restrained[i]=node["restrained_degrees_of_freedom"][1] ## todo later consider other degrees of freedom
N_displacement[i]=Vector3(node["displacement"]["x"]*15,node["displacement"]["y"]*15,node["displacement"]["z"]*15)
N_angle[i]=Vector3(node["angle"]["x"],node["angle"]["y"],node["angle"]["z"])
N_force[i]=Vector3(node["force"]["x"],node["force"]["y"],node["force"]["z"])
N_currPosition[i]=Vector3(node["position"]["x"]*15.0,node["position"]["y"]*15.0,node["position"]["z"]*15.0)
# for dynamic simulations
# append!(N_posTimeSteps,[[]])
# append!(N_angTimeSteps,[[]])
i=i+1
end
i=1
# pre-calculate the axis
for edge in edges
# element=parse(Int,edge["id"][2:end])
# find the nodes that the lements connects
fromNode = nodes[edge["source"]+1]
toNode = nodes[edge["target"]+1]
node1 = [fromNode["position"]["x"]*15.0 fromNode["position"]["y"]*15.0 fromNode["position"]["z"]*15.0]
node2 = [toNode["position"]["x"]*15.0 toNode["position"]["y"]*15.0 toNode["position"]["z"]*15.0]
length=norm(node2-node1)
axis=normalize(collect(Iterators.flatten(node2-node1)))
E_source[i]=edge["source"]+1
E_target[i]=edge["target"]+1
E_area[i]=edge["area"]
E_density[i]=edge["density"]
E_stiffness[i]=edge["stiffness"]
E_axis[i]=Vector3(axis[1],axis[2],axis[3])
E_currentRestLength[i]=length #?????? todo change
# E_currentRestLength[i]=75/sqrt(2)
N_edgeID[E_source[i],N_currEdge[E_source[i]]]=i
N_edgeFirst[E_source[i],N_currEdge[E_source[i]]]=true
N_currEdge[E_source[i]]+=1
N_edgeID[E_target[i],N_currEdge[E_target[i]]]=i
N_edgeFirst[E_target[i],N_currEdge[E_target[i]]]=false
N_currEdge[E_target[i]]+=1
# for dynamic simulations
# append!(E_stressTimeSteps,[[]])
i=i+1
end
end
function simulateParallel!(metavoxel,numTimeSteps,dt,returnEvery)
# initialize(setup)
for i in 1:numTimeSteps
#println("Timestep:",i)
doTimeStep!(metavoxel,dt,i)
if(mod(i,returnEvery)==0)
append!(displacements,[Array(metavoxel["N_displacementGPU"])])
end
end
end
########
voxCount=0
linkCount=0
nodes = setup["nodes"]
edges = setup["edges"]
voxCount=size(nodes)[1]
linkCount=size(edges)[1]
strain =0 #todooo moveeee
maxNumEdges=10
########
voxCount=0
linkCount=0
nodes = setup["nodes"]
edges = setup["edges"]
voxCount=size(nodes)[1]
linkCount=size(edges)[1]
strain =0 #todooo moveeee
############# nodes
N_position=fill(Vector3(),voxCount)
N_restrained=zeros(Bool, voxCount)
N_displacement=fill(Vector3(),voxCount)
N_angle=fill(Vector3(),voxCount)
N_currPosition=fill(Vector3(),voxCount)
N_linMom=fill(Vector3(),voxCount)
N_angMom=fill(Vector3(),voxCount)
N_intForce=fill(Vector3(),voxCount)
N_intMoment=fill(Vector3(),voxCount)
N_moment=fill(Vector3(),voxCount)
# N_posTimeSteps=[]
# N_angTimeSteps=[]
N_force=fill(Vector3(),voxCount)
N_orient=fill(Quaternion(),voxCount)
N_edgeID=fill(-1,(voxCount,maxNumEdges))
N_edgeFirst=fill(true,(voxCount,maxNumEdges))
N_currEdge=fill(1,voxCount)
############# edges
E_source=fill(0,linkCount)
E_target=fill(0,linkCount)
E_area=fill(0.0f0,linkCount)
E_density=fill(0.0f0,linkCount)
E_stiffness=fill(0.0f0,linkCount)
E_stress=fill(0.0f0,linkCount)
E_axis=fill(Vector3(1.0,0.0,0.0),linkCount)
E_currentRestLength=fill(0.0f0,linkCount)
E_pos2=fill(Vector3(),linkCount)
E_angle1v=fill(Vector3(),linkCount)
E_angle2v=fill(Vector3(),linkCount)
E_angle1=fill(Quaternion(),linkCount)
E_angle2=fill(Quaternion(),linkCount)
E_intForce1=fill(Vector3(),linkCount)
E_intMoment1=fill(Vector3(),linkCount)
E_intForce2=fill(Vector3(),linkCount)
E_intMoment2=fill(Vector3(),linkCount)
E_damp=fill(false,linkCount)
E_currentTransverseStrainSum=fill(0.0f0,linkCount)# TODO remove ot incorporate
# E_stressTimeSteps=[]
#################################################################
initialize!(setup)
#################################################################
########################## turn to cuda arrays
############# nodes
N_positionGPU= CuArray(N_position)
N_restrainedGPU= CuArray(N_restrained)
N_displacementGPU=CuArray(N_displacement)
N_angleGPU= CuArray(N_angle)
N_currPositionGPU=CuArray(N_currPosition)
N_linMomGPU= CuArray(N_linMom)
N_angMomGPU= CuArray(N_angMom)
N_intForceGPU= CuArray(N_intForce)
N_intMomentGPU= CuArray(N_intMoment)
N_momentGPU= CuArray(N_moment)
N_forceGPU= CuArray(N_force)
N_orientGPU= CuArray(N_orient)
N_edgeIDGPU= CuArray(N_edgeID)
N_edgeFirstGPU= CuArray(N_edgeFirst)
############# edges
E_sourceGPU= CuArray(E_source)
E_targetGPU= CuArray(E_target)
E_areaGPU= CuArray(E_area)
E_densityGPU= CuArray(E_density)
E_stiffnessGPU= CuArray(E_stiffness)
E_stressGPU= CuArray(E_stress)
E_axisGPU= CuArray(E_axis)
E_currentRestLengthGPU= CuArray(E_currentRestLength)
E_pos2GPU= CuArray(E_pos2)
E_angle1vGPU= CuArray(E_angle1v)
E_angle2vGPU= CuArray(E_angle2v)
E_angle1GPU= CuArray(E_angle1)
E_angle2GPU= CuArray(E_angle2)
E_currentTransverseStrainSumGPU=CuArray(E_currentTransverseStrainSum)
E_intForce1GPU= CuArray(E_intForce1)
E_intMoment1GPU= CuArray(E_intMoment1)
E_intForce2GPU= CuArray(E_intForce2)
E_intMoment2GPU= CuArray(E_intMoment2)
E_dampGPU= CuArray(E_damp)
# E_stressTimeSteps=[]
#########################################
metavoxel = Dict(
"N_positionGPU" => N_positionGPU,
"N_restrainedGPU" => N_restrainedGPU,
"N_displacementGPU" => N_displacementGPU,
"N_angleGPU" => N_angleGPU,
"N_currPositionGPU" => N_currPositionGPU,
"N_linMomGPU" => N_linMomGPU,
"N_angMomGPU" => N_angMomGPU,
"N_intForceGPU" => N_intForceGPU,
"N_intMomentGPU" => N_intMomentGPU,
"N_momentGPU" => N_momentGPU,
"N_forceGPU" => N_forceGPU,
"N_orientGPU" => N_orientGPU,
"N_edgeIDGPU" => N_edgeIDGPU,
"N_edgeFirstGPU" => N_edgeFirstGPU,
"E_sourceGPU" =>E_sourceGPU,
"E_targetGPU" =>E_targetGPU,
"E_areaGPU" =>E_areaGPU,
"E_densityGPU" =>E_densityGPU,
"E_stiffnessGPU" =>E_stiffnessGPU,
"E_stressGPU" =>E_stressGPU,
"E_axisGPU" =>E_axisGPU,
"E_currentRestLengthGPU" =>E_currentRestLengthGPU,
"E_pos2GPU" =>E_pos2GPU,
"E_angle1vGPU" =>E_angle1vGPU,
"E_angle2vGPU" =>E_angle2vGPU,
"E_angle1GPU" =>E_angle1GPU,
"E_angle2GPU" =>E_angle2GPU,
"E_currentTransverseStrainSumGPU" =>E_currentTransverseStrainSumGPU,
"E_intForce1GPU" =>E_intForce1GPU,
"E_intMoment1GPU" =>E_intMoment1GPU,
"E_intForce2GPU" =>E_intForce2GPU,
"E_intMoment2GPU" =>E_intMoment2GPU,
"E_dampGPU" =>E_dampGPU
)
#########################################
dt=0.0251646
E = 2000 # MPa
s=2.38
mass=10
MaxFreq2=E*s/mass
dt= 1/(6.283185*sqrt(MaxFreq2))
# dt=0.0001646
println("dt: $dt")
append!(displacements,[Array(metavoxel["N_displacementGPU"])])
t=@timed doTimeStep!(metavoxel,dt,0)
append!(displacements,[Array(metavoxel["N_displacementGPU"])])
time=t[2]
println("first timestep took $time seconds")
t=@timed simulateParallel!(metavoxel,numTimeSteps-1,dt,returnEvery)
time=t[2]
if save
updateDataAndSave!(metavoxel,setup,"../json/trialJuliaParallelGPUDynamic.json",displacements)
end
println("ran latticeSize $latticeSize with $voxCount voxels and $linkCount edges for $numTimeSteps time steps took $time seconds")
return
end
#####################################################
function getYoungsModulus(latticeSize,voxelSize,disp,Load,topNodesIndices)
F=-Load
l0=voxelSize*latticeSize
A=l0*l0
δl1=-mean( x.y for x in disp[topNodesIndices])
stresses=F/A
strain=δl1/l0
println("Load=$Load")
println("stress=$stresses")
E=stresses/strain
return E
end
#####################################################
function getSetup(latticeSize)
setup = Dict()
name=string("../json/setupTestUni$latticeSize",".json")
# open("../json/setupValid2.json", "r") do f
# open("../json/setupTest.json", "r") do f
# open("../json/trialJulia.json", "r") do f
# open("../json/setupTestUni4.json", "r") do f
# open("../json/setupChiral.json", "r") do f
# open("../json/setupTestCubeUni10.json", "r") do f
open(name, "r") do f
# global setup
dicttxt = String(read(f)) # file information to string
setup=JSON.parse(dicttxt) # parse and transform data
end
setup=setup["setup"]
return setup
end
#####################################################
DDisplacements=[[],[],[],[],[]]
Es=[0.0,0,0,0,0]
latticeSize =2
setup=getSetup(latticeSize)
numTimeSteps=5000
displacements=[]
save=true
returnEvery=1
runMetavoxelGPU!(setup,numTimeSteps,latticeSize,displacements,returnEvery,true)
mmm=length(displacements)
println("num displacements $mmm")
numTimeStepsRecorded=length(displacements)
d=[]
dFEA=[]
j=length(displacements[end])
step=100
for i in 1:step:numTimeStepsRecorded
append!(d,displacements[i][j].y)
end
DDisplacements[latticeSize]=d
# E2=getYoungsModulus(latticeSize,75,displacements[end],Load,topNodesIndices)
# Es[latticeSize]=E2
println("converged displacement= $(displacements[numTimeStepsRecorded][j].y)")
plot(1:step:numTimeStepsRecorded,d,label="Dynamic",xlabel="timestep",ylabel="displacement",title="$latticeSize Voxel Convergence Study")
# savefig("4_voxel_convergence")
#####################################################
# n=[]
# nFEA=[]
# j=length(displacements[end])
# for i in 1:j
# append!(n,displacements[end][i].y)
# end
# scatter(1:j,n,label="Dyanmic",xlabel="Node ID",ylabel="displacement",title="Node Displacement")
#####################################################
#####################################################