{ "cells": [ { "cell_type": "code", "execution_count": 148, "metadata": {}, "outputs": [], "source": [ "using LinearAlgebra\n", "using Plots\n", "import JSON\n", "using StaticArrays, Rotations\n", "# BASED ON https://github.com/jonhiller/Voxelyze" ] }, { "cell_type": "code", "execution_count": 149, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "simulateParallel (generic function with 3 methods)" ] }, "execution_count": 149, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function simulateParallel(setup,numTimeSteps,dt,static=true,saveInterval=10)\n", "\tinitialize(setup)\n", " for i in 1:numTimeSteps\n", " # println(\"Timestep:\",i)\n", " doTimeStep(setup,dt,static,i,saveInterval);\n", " end\n", "end" ] }, { "cell_type": "code", "execution_count": 150, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "initialize (generic function with 1 method)" ] }, "execution_count": 150, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function initialize(setup)\n", "\tnodes = setup[\"nodes\"]\n", " edges = setup[\"edges\"]\n", "\t# pre-calculate current position\n", "\tfor node in nodes\n", " # element=parse(Int,node[\"id\"][2:end])\n", "\n", " append!(N_position,[[node[\"position\"][\"x\"] node[\"position\"][\"y\"] node[\"position\"][\"z\"]]])\n", " append!(N_degrees_of_freedom,[node[\"degrees_of_freedom\"]])\n", " append!(N_restrained_degrees_of_freedom, [node[\"restrained_degrees_of_freedom\"]])\n", " append!(N_displacement,[[node[\"displacement\"][\"x\"] node[\"displacement\"][\"y\"] node[\"displacement\"][\"z\"]]])\n", " append!(N_angle,[[node[\"angle\"][\"x\"] node[\"angle\"][\"y\"] node[\"angle\"][\"z\"]]])\n", " append!(N_force,[[node[\"force\"][\"x\"] node[\"force\"][\"y\"] node[\"force\"][\"z\"]]])\n", " append!(N_currPosition,[[node[\"position\"][\"x\"] node[\"position\"][\"y\"] node[\"position\"][\"z\"]]])\n", " append!(N_orient,[[1.0 0.0 0.0 0.0]])#quat\n", " append!(N_linMom,[[0 0 0]])\n", " append!(N_angMom,[[0 0 0]])\n", " append!(N_intForce,[[0 0 0]])\n", " append!(N_intMoment,[[0 0 0]])\n", " append!(N_moment,[[0 0 0]])\n", " \n", " # for dynamic simulations\n", " append!(N_posTimeSteps,[[]])\n", " append!(N_angTimeSteps,[[]])\n", " \n", "\tend \n", "\t# pre-calculate the axis\n", "\tfor edge in edges\n", " # element=parse(Int,edge[\"id\"][2:end])\n", " \n", " # find the nodes that the lements connects\n", " fromNode = nodes[edge[\"source\"]+1]\n", " toNode = nodes[edge[\"target\"]+1]\n", "\n", " \n", " node1 = [fromNode[\"position\"][\"x\"] fromNode[\"position\"][\"y\"] fromNode[\"position\"][\"z\"]]\n", " node2 = [toNode[\"position\"][\"x\"] toNode[\"position\"][\"y\"] toNode[\"position\"][\"z\"]]\n", " \n", " length=norm(node2-node1)\n", " axis=normalize(collect(Iterators.flatten(node2-node1)))\n", " \n", " append!(E_source,[edge[\"source\"]+1])\n", " append!(E_target,[edge[\"target\"]+1])\n", " append!(E_area,[edge[\"area\"]])\n", "# append!(E_density,[edge[\"density\"]])\n", "# append!(E_stiffness,[edge[\"stiffness\"]])\n", " append!(E_density,[1000])\n", " append!(E_stiffness,[1000000])\n", " append!(E_stress,[0])\n", " append!(E_axis,[axis])\n", " append!(E_currentRestLength,[length])\n", " append!(E_pos2,[[0 0 0]])\n", " append!(E_angle1v,[[0 0 0]])\n", " append!(E_angle2v,[[0 0 0]])\n", " append!(E_angle1,[[1.0 0.0 0.0 0.0]]) #quat\n", " append!(E_angle2,[[1.0 0.0 0.0 0.0]]) #quat\n", " append!(E_currentTransverseStrainSum,[0])\n", " \n", " # for dynamic simulations\n", " append!(E_stressTimeSteps,[[]])\n", " \n", "\tend \n", "\t\n", "end" ] }, { "cell_type": "code", "execution_count": 151, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "doTimeStep (generic function with 1 method)" ] }, "execution_count": 151, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function doTimeStep(setup,dt,static,currentTimeStep,saveInterval)\n", " \n", " nodes = setup[\"nodes\"]\n", " edges = setup[\"edges\"]\n", " voxCount=size(nodes)[1]\n", " linkCount=size(edges)[1]\n", "\n", "\tif dt==0 \n", "\t\treturn true\n", "\telseif (dt<0) \n", "\t\tdt = recommendedTimeStep()\n", " end\n", "\n", "\t# if (collisions) updateCollisions();\n", "\tcollisions=false\n", "\n", "\t# Euler integration:\n", "\tDiverged = false\n", " # for edge in edges\n", " \n", "\tfor i in 1:linkCount\n", " # fromNode = nodes[edge[\"source\"]+1]\n", " # toNode = nodes[edge[\"target\"]+1]\n", " # node1 = [fromNode[\"position\"][\"x\"] fromNode[\"position\"][\"y\"] fromNode[\"position\"][\"z\"]]\n", " # node2 = [toNode[\"position\"][\"x\"] toNode[\"position\"][\"y\"] toNode[\"position\"][\"z\"]]\n", " # updateForces(setup,edge,node1,node2,static)# element numbers??\n", " updateForces(setup,i,static)# element numbers??\n", " # todo: update forces and whatever\n", "\t\tif axialStrain(true) > 100\n", "\t\t\tDiverged = true; # catch divergent condition! (if any thread sets true we will fail, so don't need mutex...\n", " end\n", " end\n", " \n", " \n", " if Diverged\n", "\t\tprintln(\"Divergedd!!!!!\")\n", "\t\treturn false\n", " end\n", " \n", "\tfor i in 1:voxCount\n", "\t\ttimeStep(dt,i,static,currentTimeStep)\n", " # timeStep(dt,node,static,currentTimeStep)\n", "\t\tif(!static&& currentTimeStep%saveInterval==0)\n", " append!(N_posTimeSteps[i],[N_displacement[i]])\n", " append!(N_angTimeSteps[i],[N_angle[i]])\n", "\n", " end\n", "\t\t# todo: update linMom,angMom, orient and whatever\n", " end\n", "\n", "\t\n", "\tcurrentTimeStep = currentTimeStep+dt\n", "\treturn true\n", "end" ] }, { "cell_type": "code", "execution_count": 152, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "updateForces (generic function with 2 methods)" ] }, "execution_count": 152, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function updateForces(setup,edge,static=true)\n", " \n", "\t# pVNeg=new THREE.Vector3(node1.position.x,node1.position.y,node1.position.z);\n", "\t# pVPos=new THREE.Vector3(node2.position.x,node2.position.y,node2.position.z);\n", " # currentRestLength=pVPos.clone().sub(pVNeg).length();\n", "\t# edge.currentRestLength=currentRestLength; # todo make sure updated\n", " \n", "\tnode1=E_source[edge]\n", " node2=E_target[edge]\n", " \n", " currentRestLength=E_currentRestLength[edge]\n", " \n", " \n", "\tpVNeg=copy(N_currPosition[node1])# todo change to be linked to edge not node \n", "\tpVPos=copy(N_currPosition[node2])# todo change to be linked to edge not node\n", " \n", " \n", "\t# Vec3D<double> three\n", "\toldPos2 = copy(E_pos2[edge])\n", "\toldAngle1v = copy(E_angle1v[edge])\n", "\toldAngle2v = copy(E_angle2v[edge])# remember the positions/angles from last timestep to calculate velocity\n", "\t# var oldAngle1v=new THREE.Vector3(node1.angle.x,node1.angle.y,node1.angle.z);//?\n", "\t# var oldAngle2v=new THREE.Vector3(node2.angle.x,node2.angle.y,node2.angle.z); //??\n", " \n", "\ttotalRot= orientLink(edge) # sets pos2, angle1, angle2 /*restLength*/\n", " \n", "\n", "\tdPos2=0.5*(copy(E_pos2[edge])-oldPos2)\n", "\tdAngle1=0.5*(copy(E_angle1v[edge])-oldAngle1v)\n", "\tdAngle2=0.5*(copy(E_angle2v[edge])-oldAngle2v)\n", " \n", " \n", "\n", "\t# if volume effects...\n", " # if (!mat->isXyzIndependent() || currentTransverseStrainSum != 0) \n", " # updateTransverseInfo(); //currentTransverseStrainSum != 0 catches when we disable poissons mid-simulation\n", "\n", "\t\n", " _stress=updateStrain((E_pos2[edge][1]/E_currentRestLength[edge]),E_stiffness[edge])\n", " # var _stress=updateStrain(1.0);\n", " \n", "\n", "\tE_stress[edge] = _stress\n", "\tif !static\n", " append!(E_stressTimeSteps[edge],[_stress])\n", " end\n", " \n", " ######### check this\n", "\tif setup[\"viz\"][\"minStress\"]>_stress\n", "\t\tsetup[\"viz\"][\"minStress\"]=_stress\n", "\telseif setup[\"viz\"][\"maxStress\"]<_stress\n", "\t\tsetup[\"viz\"][\"maxStress\"]=_stress\n", " end\n", " \n", " \n", "\t# if (isFailed()){forceNeg = forcePos = momentNeg = momentPos = Vec3D<double>(0,0,0); return;}\n", "\n", "\t# var b1=mat->_b1, b2=mat->_b2, b3=mat->_b3, a2=mat->_a2; //local copies //todo get from where i had\n", "\t\n", "\tl = currentRestLength # ??\n", "\trho = E_density[edge] \n", "\tA = E_area[edge] \n", "\tE = E_stiffness[edge] # youngs modulus\n", "\tG=1.0 # todo shear_modulus\n", "\tixx = 1.0 # todo section ixx\n", "\tI=1.0\n", "\tiyy = 1.0 # todo section.iyy//\n", "\t# var l0=length.dataSync();\n", "\tJ=1.0;# todo check\n", "\t# var l02 = l0 * l0;\n", "\t# var l03 = l0 * l0 * l0;\n", "\tb1= 12*E*I/(l*l*l)\n", "\tb2= 6*E*I/(l*l)\n", "\tb3= 2*E*I/(l)\n", "\ta1= E*A/l\n", "\ta2= G*J/l\n", "\tnu=0\n", "\n", "\tb1= 5e6\n", "\tb2= 1.25e7\n", "\tb3= 2.08333e+07\n", "\ta1= E*A/l\n", "\ta2= 1.04167e+07\n", "\n", "\tL = 5;\n", "\ta1 = E*L # EA/L : Units of N/m\n", "\ta2 = E * L*L*L / (12.0*(1+nu)) # GJ/L : Units of N-m\n", "\tb1 = E*L # 12EI/L^3 : Units of N/m\n", "\tb2 = E*L*L/2.0 # 6EI/L^2 : Units of N (or N-m/m: torque related to linear distance)\n", "\tb3 = E*L*L*L/6.0 # 2EI/L : Units of N-m\n", "\t# console.log(\"currentRestLength:\"+currentRestLength);\n", "\t# console.log(\"b1:\"+b1/10e6);\n", "\t# console.log(\"b2:\"+b2/10e7);\n", "\t# console.log(\"b3:\"+b3/10e7);\n", "\t# console.log(\"a2:\"+a2/10e7);\n", "\t# var b1= 5e6;\n", "\t# var b2= 1.25e7;\n", "\t# var b3= 2.08333e+07;\n", "\t# var a1= E*A/l;\n", "\t# var a2= 1.04167e+07;\n", " \n", "\tcurrentTransverseArea=25.0 # todo ?? later change\n", "\tcurrentTransverseArea=A\n", "\n", "\t# Beam equations. All relevant terms are here, even though some are zero for small angle and others are zero for large angle (profiled as negligible performance penalty)\n", " forceNeg = [(_stress*currentTransverseArea) (b1*E_pos2[edge][2]-b2*(E_angle1v[edge][3] + E_angle2v[edge][3])) (b1*E_pos2[edge][3] + b2*(E_angle1v[edge][2] + E_angle2v[edge][2]))] # Use Curstress instead of -a1*Pos2.x to account for non-linear deformation \n", "\tforcePos = -forceNeg;\n", "\n", "\tmomentNeg = [(a2*(E_angle2v[edge][1]-E_angle1v[edge][1])) (-b2*E_pos2[edge][3]-b3*(2*E_angle1v[edge][2]+E_angle2v[edge][2])) (b2*E_pos2[edge][2] - b3*(2*E_angle1v[edge][3] + E_angle2v[edge][3]))]\n", "\tmomentPos = [(a2*(E_angle1v[edge][1]-E_angle2v[edge][1])) (-b2*E_pos2[edge][3]- b3*(E_angle1v[edge][2]+2*E_angle2v[edge][2])) (b2*E_pos2[edge][2] - b3*(E_angle1v[edge][3] + 2*E_angle2v[edge][3]))]\n", "\t\n", "\t\t\t\t\t\t\t\t\n", "\t# //local damping:\n", "\t# if (isLocalVelocityValid()){ //if we don't have the basis for a good damping calculation, don't do any damping.\n", "\t# \tfloat sqA1=mat->_sqA1, sqA2xIp=mat->_sqA2xIp,sqB1=mat->_sqB1, sqB2xFMp=mat->_sqB2xFMp, sqB3xIp=mat->_sqB3xIp;\n", "\t# \tVec3D<double> posCalc(\tsqA1*dPos2.x,\n", "\t# \t\t\t\t\t\t\tsqB1*dPos2.y - sqB2xFMp*(dAngle1.z+dAngle2.z),\n", "\t# \t\t\t\t\t\t\tsqB1*dPos2.z + sqB2xFMp*(dAngle1.y+dAngle2.y));\n", "\n", "\t# \tforceNeg += pVNeg->dampingMultiplier()*posCalc;\n", "\t# \tforcePos -= pVPos->dampingMultiplier()*posCalc;\n", "\n", "\t# \tmomentNeg -= 0.5*pVNeg->dampingMultiplier()*Vec3D<>(\t-sqA2xIp*(dAngle2.x - dAngle1.x),\n", "\t# \t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsqB2xFMp*dPos2.z + sqB3xIp*(2*dAngle1.y + dAngle2.y),\n", "\t# \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t-sqB2xFMp*dPos2.y + sqB3xIp*(2*dAngle1.z + dAngle2.z));\n", "\t# \tmomentPos -= 0.5*pVPos->dampingMultiplier()*Vec3D<>(\tsqA2xIp*(dAngle2.x - dAngle1.x),\n", "\t# \t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsqB2xFMp*dPos2.z + sqB3xIp*(dAngle1.y + 2*dAngle2.y),\n", "\t# \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t-sqB2xFMp*dPos2.y + sqB3xIp*(dAngle1.z + 2*dAngle2.z));\n", "\n", "\t# }\n", "\t# else setBoolState(LOCAL_VELOCITY_VALID, true); //we're good for next go-around unless something changes\n", "\n", " #\ttransform forces and moments to local voxel coordinates\n", "\tsmallAngle=false # ?? todo check\n", " \n", "\n", "\tif !smallAngle # ?? chech\n", "\t\tforceNeg = RotateVec3DInv(E_angle1[edge],forceNeg)\n", "\t\tmomentNeg = RotateVec3DInv(E_angle1[edge],momentNeg)\n", " end\n", " \n", "\n", " \n", "\n", "\n", "\tforcePos = RotateVec3DInv(E_angle2[edge],forcePos);\n", "\tmomentPos = RotateVec3DInv(E_angle2[edge],momentPos);\n", "\n", " # println(momentPos)\n", "\n", "\tforceNeg =toAxisOriginalVector3(forceNeg,E_axis[edge]);\n", "\tforcePos =toAxisOriginalVector3(forcePos,E_axis[edge]);\n", " \n", "\tmomentNeg=toAxisOriginalQuat(momentNeg,E_axis[edge]);# TODOO CHECKKKKKK\n", "\tmomentPos=toAxisOriginalQuat(momentPos,E_axis[edge]);\n", " \n", " # println(momentPos[2],\" \",momentPos[3],\" \",momentPos[4],\" \",momentPos[1],\" \")\n", "\n", "\tN_intForce[node1] =N_intForce[node1] +(forceNeg) ;\n", "\tN_intForce[node2] =N_intForce[node2] +(forcePos) ;\n", " # println(N_intMoment[node2])\n", "\tN_intMoment[node1]=[(N_intMoment[node1][1]+momentNeg[2]) (N_intMoment[node1][2]+momentNeg[3]) (N_intMoment[node2][3]+momentPos[4])];\n", "\tN_intMoment[node2]=[(N_intMoment[node2][1]+momentPos[2]) (N_intMoment[node2][2]+momentPos[3]) (N_intMoment[node2][3]+momentPos[4])];\n", " # println(N_intMoment[node2])\n", "\t# assert(!(forceNeg.x != forceNeg.x) || !(forceNeg.y != forceNeg.y) || !(forceNeg.z != forceNeg.z)); //assert non QNAN\n", "\t# assert(!(forcePos.x != forcePos.x) || !(forcePos.y != forcePos.y) || !(forcePos.z != forcePos.z)); //assert non QNAN\n", " \n", "\n", "end" ] }, { "cell_type": "code", "execution_count": 172, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "orientLink (generic function with 1 method)" ] }, "execution_count": 172, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function orientLink( edge) # updates pos2, angle1, angle2, and smallAngle //Quat3D<double> /*double restLength*/\n", " node1=E_source[edge]\n", " node2=E_target[edge]\n", " currentRestLength=E_currentRestLength[edge]\n", "\tpVNeg=copy(N_currPosition[node1])# todo change to be linked to edge not node \n", "\tpVPos=copy(N_currPosition[node2])# todo change to be linked to edge not node\n", "\tpos2 = toAxisXVector3(pVPos-pVNeg,E_axis[edge]) # digit truncation happens here...\n", " # pos2.x = Math.round(pos2.x * 1e4) / 1e4; \n", "\tangle1 = toAxisXQuat(N_orient[node1],E_axis[edge])\n", "\tangle2 = toAxisXQuat(N_orient[node2],E_axis[edge])\n", " # println(angle1[2],\" \",angle1[3],\" \",angle1[4],\" \",angle1[1])\n", "\ttotalRot = conjugate(angle1) #keep track of the total rotation of this bond (after toAxisX()) # Quat3D<double>\n", " pos2 = RotateVec3D(totalRot,pos2)\n", " print(\"pos2 \")\n", " println(pos2)\n", " \n", "\n", "\t# angle2 = copy(totalRot) .* angle2 # todo .*\n", " angle2=[angle2[1]*totalRot[1] angle2[2]*totalRot[2] angle2[3]*totalRot[3] angle2[4]*totalRot[4]]\n", "\tangle1 = [1.0 0.0 0.0 0.0]#new THREE.Quaternion() #zero for now...\n", " \n", "\n", "\t# small angle approximation?\n", "\t# var SmallTurn = ((Math.abs(pos2.z)+Math.abs(pos2.y))/pos2.x);\n", "\t# var ExtendPerc = (Math.abs(1-pos2.x/currentRestLength));\n", "\t# if (!smallAngle /*&& angle2.IsSmallAngle()*/ && SmallTurn < SA_BOND_BEND_RAD && ExtendPerc < SA_BOND_EXT_PERC){\n", "\t# \tsmallAngle = true;\n", "\t# \tsetBoolState(LOCAL_VELOCITY_VALID, false);\n", "\t# }\n", "\t# else if (smallAngle && (/*!angle2.IsSmallishAngle() || */SmallTurn > HYSTERESIS_FACTOR*SA_BOND_BEND_RAD || ExtendPerc > HYSTERESIS_FACTOR*SA_BOND_EXT_PERC)){\n", "\t# \tsmallAngle = false;\n", "\t# \tsetBoolState(LOCAL_VELOCITY_VALID, false);\n", " # }\n", " \n", " smallAngle=true #todo later remove\n", "\n", "\tif (smallAngle)\t #Align so Angle1 is all zeros\n", "\t\tpos2[1] =pos2[1]- currentRestLength #only valid for small angles\n", " else #Large angle. Align so that Pos2.y, Pos2.z are zero.\n", "\t\t# FromAngleToPosX(angle1,pos2) #get the angle to align Pos2 with the X axis\n", "\t\t# totalRot = angle1.clone().multiply(totalRot) #update our total rotation to reflect this\n", "\t\t# angle2 = angle1.clone().multiply( angle2) #rotate angle2\n", "\t\t# pos2 = new THREE.Vector3(pos2.length() - currentRestLength, 0, 0);\n", " end\n", " \n", "\n", "\tangle1v = ToRotationVector(angle1)\n", "\tangle2v = ToRotationVector(angle2)\n", "\n", "\t# assert(!(angle1v.x != angle1v.x) || !(angle1v.y != angle1v.y) || !(angle1v.z != angle1v.z)); # assert non QNAN\n", "\t# assert(!(angle2v.x != angle2v.x) || !(angle2v.y != angle2v.y) || !(angle2v.z != angle2v.z)); # assert non QNAN\n", " \n", " E_pos2[edge]=copy(pos2)\n", " E_angle1v[edge]=copy(angle1v)\n", " E_angle2v[edge]=copy(angle2v)\n", " E_angle1[edge]=copy(angle1)\n", " E_angle2[edge]=copy(angle2)\n", " \n", " print(\"angle1v \")\n", " println(angle1v)\n", " print(\"angle2v \")\n", " println(angle2v)\n", " \n", "\n", "\treturn totalRot\n", "end" ] }, { "cell_type": "code", "execution_count": 154, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "RotateVec3DInv (generic function with 1 method)" ] }, "execution_count": 154, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function RotateVec3D(a, f) \n", "\tfx= (f[1]==-0) ? 0 : f[1]\n", " fy= (f[2]==-0) ? 0 : f[2]\n", " fz= (f[3]==-0) ? 0 : f[3]\n", " # fx= f[1]\n", " # fy= f[2]\n", " # fz= f[3]\n", "\ttw = fx*a[2] + fy*a[3] + fz*a[4]\n", "\ttx = fx*a[1] - fy*a[4] + fz*a[3]\n", "\tty = fx*a[4] + fy*a[1] - fz*a[2]\n", "\ttz = -fx*a[3] + fy*a[2] + fz*a[1]\n", "\n", "\treturn [(a[1]*tx+a[2][2]*tw+a[3]*tz-a[4]*ty) (a[1]*ty-a[2]*tz+a[3]*tw+a[4]*tx) (a[1]*tz+a[2]*ty-a[3]*tx + a[4]*tw)]\n", "end\n", "#!< Returns a vector representing the specified vector \"f\" rotated by this quaternion. @param[in] f The vector to transform.\n", "function RotateVec3DInv(a, f) \n", " fx=f[1]\n", " fy=f[2]\n", " fz=f[3]\n", " tw = a[2]*fx + a[3]*fy + a[4]*fz\n", " tx = a[1]*fx - a[3]*fz + a[4]*fy\n", " ty = a[1]*fy + a[2]*fz - a[4]*fx\n", " tz = a[1]*fz - a[2]*fy + a[3]*fx\n", " return [(tw*a[2] + tx*a[1] + ty*a[4] - tz*a[3]) (tw*a[3] - tx*a[4] + ty*a[1] + tz*a[2]) (tw*a[4] + tx*a[3] - ty*a[2] + tz*a[1])]\t\n", "end\n", "#!< 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.\n" ] }, { "cell_type": "code", "execution_count": 155, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "conjugate (generic function with 1 method)" ] }, "execution_count": 155, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function setFromUnitVectors(vFrom, vTo )\n", " # assumes direction vectors vFrom and vTo are normalized\n", " EPS = 0.000001;\n", " r = dot(vFrom,vTo)+1\n", "\n", " if r < EPS\n", " r = 0;\n", " if abs( vFrom[1] ) > abs( vFrom[3] ) \n", " qx = - vFrom[2]\n", " qy = vFrom[1]\n", " qz = 0\n", " qw = r\n", " else \n", " qx = 0\n", " qy = - vFrom[3]\n", " qz = vFrom[2]\n", " qw = r\n", " end\n", " else \n", " # crossVectors( vFrom, vTo ); // inlined to avoid cyclic dependency on Vector3\n", " qx = vFrom[2] * vTo[3] - vFrom[3] * vTo[2]\n", " qy = vFrom[3] * vTo[1] - vFrom[1] * vTo[3]\n", " qz = vFrom[1] * vTo[2] - vFrom[2] * vTo[1]\n", " qw = r\n", "\n", " end\n", " qx= (qx==-0) ? 0 : qx\n", " qy= (qy==-0) ? 0 : qy\n", " qz= (qz==-0) ? 0 : qz\n", " qw= (qw==-0) ? 0 : qw\n", " nn=normalize(collect(Iterators.flatten([qw,qx,qy,qz])))\n", " return [nn[1] nn[2] nn[3] nn[4]]\n", "\n", "end\n", "\n", "function normalizeQ(q) \n", " l = norm(q)\n", " if l === 0 \n", " qx = 0\n", " qy = 0\n", " qz = 0\n", " qw = 1\n", " else \n", " l = 1 / l\n", " qx = q[2] * l\n", " qy = q[3] * l\n", " qz = q[4] * l\n", " qw = q[1] * l\n", " end\n", " return [qw qx qy qz]\n", "end\n", "\n", "function conjugate(q)\n", " x= (-q[2]==-0) ? 0 : -q[2]\n", " y= (-q[3]==-0) ? 0 : -q[3]\n", " z= (-q[4]==-0) ? 0 : -q[4]\n", "\n", " return [q[1] x y z]\n", "end" ] }, { "cell_type": "code", "execution_count": 156, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "applyQuaternion1 (generic function with 1 method)" ] }, "execution_count": 156, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function applyQuaternion(q1,q2)\n", " x = q1[2]\n", " y = q1[3]\n", " z = q1[4]\n", " w = q1[1]\n", " qx = q2[2]\n", " qy = q2[3]\n", " qz = q2[4]\n", " qw = q2[1]\n", "\n", " # calculate quat * vector\n", "\n", " ix = qw * x + qy * z - qz * y\n", " iy = qw * y + qz * x - qx * z\n", " iz = qw * z + qx * y - qy * x\n", " iw = - qx * x - qy * y - qz * z\n", "\n", " # calculate result * inverse quat\n", "\n", " xx = ix * qw + iw * - qx + iy * - qz - iz * - qy\n", " yy = iy * qw + iw * - qy + iz * - qx - ix * - qz\n", " zz = iz * qw + iw * - qz + ix * - qy - iy * - qx\n", "\n", " mm=normalize(collect(Iterators.flatten([xx yy zz])))\n", " return [mm[1] mm[2] mm[3]]\n", "end\n", "\n", "function applyQuaternion1(e,q2)\n", " x = e[1]\n", " y = e[2]\n", " z = e[3]\n", "\n", " qx = q2[2]\n", " qy = q2[3]\n", " qz = q2[4]\n", " qw = q2[1]\n", "\n", " # calculate quat * vector\n", "\n", " ix = qw * x + qy * z - qz * y\n", " iy = qw * y + qz * x - qx * z\n", " iz = qw * z + qx * y - qy * x\n", " iw = - qx * x - qy * y - qz * z\n", "\n", " # calculate result * inverse quat\n", "\n", " xx = ix * qw + iw * - qx + iy * - qz - iz * - qy\n", " yy = iy * qw + iw * - qy + iz * - qx - ix * - qz\n", " zz = iz * qw + iw * - qz + ix * - qy - iy * - qx\n", "\n", " return [xx yy zz]\n", "end" ] }, { "cell_type": "code", "execution_count": 157, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "setFromRotationMatrix (generic function with 1 method)" ] }, "execution_count": 157, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function setQuaternionFromEuler(euler)\n", " x=euler[1]\n", " y=euler[2]\n", " z=euler[3]\n", " \n", " c1 = cos( x / 2 )\n", " c2 = cos( y / 2 )\n", " c3 = cos( z / 2 )\n", "\n", " s1 = sin( x / 2 )\n", " s2 = sin( y / 2 )\n", " s3 = sin( z / 2 )\n", " \n", " x = s1 * c2 * c3 + c1 * s2 * s3\n", " y = c1 * s2 * c3 - s1 * c2 * s3\n", " z = c1 * c2 * s3 + s1 * s2 * c3\n", " w = c1 * c2 * c3 - s1 * s2 * s3\n", " \n", " return [w x y z]\n", "end\n", "\n", "function quatToMatrix( quaternion )\n", "\n", " te = zeros(16)\n", "\n", " x = quaternion[2]\n", " y = quaternion[3]\n", " z = quaternion[4]\n", " w = quaternion[1]\n", " \n", " x2 = x + x\n", " y2 = y + y\n", " z2 = z + z\n", " xx = x * x2\n", " xy = x * y2\n", " xz = x * z2\n", " yy = y * y2\n", " yz = y * z2\n", " zz = z * z2\n", " wx = w * x2\n", " wy = w * y2\n", " wz = w * z2\n", "\n", " sx = 1\n", " sy = 1\n", " sz = 1\n", "\n", " te[ 1 ] = ( 1 - ( yy + zz ) ) * sx\n", " te[ 2 ] = ( xy + wz ) * sx\n", " te[ 3 ] = ( xz - wy ) * sx\n", " te[ 4 ] = 0;\n", "\n", " te[ 5 ] = ( xy - wz ) * sy\n", " te[ 6 ] = ( 1 - ( xx + zz ) ) * sy\n", " te[ 7 ] = ( yz + wx ) * sy\n", " te[ 8 ] = 0;\n", "\n", " te[ 9 ] = ( xz + wy ) * sz\n", " te[ 10 ] = ( yz - wx ) * sz\n", " te[ 11 ] = ( 1 - ( xx + yy ) ) * sz\n", " te[ 12 ] = 0\n", "\n", " te[ 13 ] = 0 #position.x;\n", " te[ 14 ] = 0 #position.y;\n", " te[ 15 ] = 0 #position.z;\n", " te[ 16 ] = 1\n", "\n", " return te\n", "\n", "end\n", "\n", "function setFromRotationMatrix(m)\n", " te = m\n", " m11 = (te[ 1 ]== -0.0) ? 0.0 : te[ 1 ]\n", " m12 = (te[ 5 ]== -0.0) ? 0.0 : te[ 5 ]\n", " m13 = (te[ 9 ]== -0.0) ? 0.0 : te[ 9 ]\n", " m21 = (te[ 2 ]== -0.0) ? 0.0 : te[ 2 ]\n", " m22 = (te[ 6 ]== -0.0) ? 0.0 : te[ 6 ]\n", " m23 = (te[ 10]== -0.0) ? 0.0 : te[ 10]\n", " m31 = (te[ 3 ]== -0.0) ? 0.0 : te[ 3 ]\n", " m32 = (te[ 7 ]== -0.0) ? 0.0 : te[ 7 ]\n", " m33 = (te[ 11]== -0.0) ? 0.0 : te[ 11]\n", "\n", " m11 = te[ 1 ]\n", " m12 = te[ 5 ]\n", " m13 = te[ 9 ]\n", " m21 = te[ 2 ]\n", " m22 = te[ 6 ]\n", " m23 = te[ 10]\n", " m31 = te[ 3 ]\n", " m32 = te[ 7 ]\n", " m33 = te[ 11]\n", "\n", "\n", "\n", " y = asin( clamp( m13, - 1, 1 ) )\n", "\n", " if ( abs( m13 ) < 0.9999999 ) \n", " \n", " x = atan( - m23, m33 )\n", " z = atan( - m12, m11 )#-m12, m11\n", " # if(m23==0.0)\n", " # x = atan( m23, m33 )\n", " # end\n", " # if(m12==0.0)\n", " # z = atan( m12, m11 )\n", " # end\n", "\n", " else\n", "\n", " x = atan( m32, m22 )\n", " z = 0;\n", "\n", " end\n", " \n", " return [x y z]\n", " \n", "end" ] }, { "cell_type": "code", "execution_count": 158, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "toAxisXVector3 (generic function with 1 method)" ] }, "execution_count": 158, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function toAxisOriginalVector3(pV,axis)\n", " # xaxis=[1 0 0]\n", " \n", " # vector=copy(axis)\n", " # vector=normalize(collect(Iterators.flatten(vector)))\n", "\n", " # p = SVector(pV[1],pV[2], pV[3])\n", " # q=setFromUnitVectors(xaxis, vector)\n", " \n", " # v= q * p\n", " # return [v[1] v[2] v[3]]\n", "\n", " xaxis=[1 0 0]\n", "\n", " vector=copy(axis)\n", " vector=normalize(collect(Iterators.flatten(vector)))\n", "\n", " p = SVector(pV[1],pV[2], pV[3]) \n", "\n", " q=setFromUnitVectors(xaxis, vector)\n", " \n", "# d=17\n", "# qw=round(q[1], digits=d)\n", "# qx=round(q[2], digits=d)\n", "# qy=round(q[3], digits=d)\n", "# qz=round(q[4], digits=d)\n", " qw=q[1]\n", " qx=q[2]\n", " qy=q[3]\n", " qz=q[4]\n", "\n", " rot=setFromRotationMatrix(copy(quatToMatrix( copy([qw qx qy qz]) )))\n", "\n", " return applyQuaternion1( copy(pV) ,setQuaternionFromEuler(copy(rot)) )\n", "end\n", "\n", "function toAxisXVector3(pV,axis) #TODO CHANGE\n", " # xaxis=[1 0 0]\n", " # vector=copy(axis)\n", " # vector=normalize(collect(Iterators.flatten(vector)))\n", " # p = SVector(pV[1],pV[2], pV[3])\n", " # q=setFromUnitVectors(vector,xaxis)\n", " \n", " # v= q * p\n", " # return [v[1] v[2] v[3]]\n", "\n", " xaxis=[1 0 0]\n", "\n", " vector=copy(axis)\n", " vector=normalize(collect(Iterators.flatten(vector)))\n", "\n", " p = SVector(pV[1],pV[2], pV[3]) \n", "\n", " q=setFromUnitVectors(vector,xaxis)\n", " \n", " d=17\n", " qw=round(q[1], digits=d)\n", " qx=round(q[2], digits=d)\n", " qy=round(q[3], digits=d)\n", " qz=round(q[4], digits=d)\n", " \n", " rot=setFromRotationMatrix(copy(quatToMatrix( copy([qw qx qy qz]) )))\n", "\n", " return applyQuaternion1( copy(pV) ,setQuaternionFromEuler(copy(rot)) )\n", "end\n", "#transforms a vec3D in the original orientation of the bond to that as if the bond was in +X direction" ] }, { "cell_type": "code", "execution_count": 159, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "toAxisXQuat (generic function with 1 method)" ] }, "execution_count": 159, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function toAxisOriginalQuat(pQ,axis)\n", " # xaxis=[1 0 0] \n", " # vector=copy(axis)\n", " # vector=normalize(collect(Iterators.flatten(vector)))\n", "\n", " # p = SVector(pQ[1],pQ[2], pQ[3])\n", " # q=setFromUnitVectors(xaxis, vector)\n", " \n", " # v=q * p\n", " # return Quat(1.0,v[1],v[2],v[3])\n", "\n", " xaxis=[1 0 0]\n", "\n", " vector=copy(axis)\n", " vector=normalize(collect(Iterators.flatten(vector)))\n", "\n", " \n", " p = SVector(pQ[1],pQ[2], pQ[3]) \n", "\n", " q=setFromUnitVectors(xaxis,vector)\n", " \n", "# d=17\n", "# qw=round(q[1], digits=d)\n", "# qx=round(q[2], digits=d)\n", "# qy=round(q[3], digits=d)\n", "# qz=round(q[4], digits=d)\n", " qw=q[1]\n", " qx=q[2]\n", " qy=q[3]\n", " qz=q[4]\n", "\n", " rot=setFromRotationMatrix(copy(quatToMatrix( copy([qw qx qy qz]) )))\n", " v=applyQuaternion1( copy([pQ[1] pQ[2] pQ[3]]) ,setQuaternionFromEuler(copy(rot)) )\n", "\n", " return [1.0 v[1] v[2] v[3]]\n", " \n", "end\n", "\n", "function toAxisXQuat(pQ,axis)\n", " # xaxis=[1 0 0] \n", " # vector=copy(axis)\n", " # vector=normalize(collect(Iterators.flatten(vector)))\n", "\n", " # p = SVector(q.x,q.y, q.z)\n", " # q=setFromUnitVectors(vector,xaxis)\n", " \n", " # v=q * p\n", " # return Quat(q.w,v[1],v[2],v[3])\n", "\n", " xaxis=[1 0 0]\n", "\n", " vector=copy(axis)\n", " vector=normalize(collect(Iterators.flatten(vector)))\n", "\n", " p = SVector(pQ[2],pQ[3],pQ[4]) \n", "\n", " q=setFromUnitVectors(vector,xaxis)\n", " \n", " d=17\n", " qw=round(q[1], digits=d)\n", " qx=round(q[2], digits=d)\n", " qy=round(q[3], digits=d)\n", " qz=round(q[4], digits=d)\n", "\n", " rot=setFromRotationMatrix(copy(quatToMatrix( copy([qw qx qy qz]) )))\n", " v=applyQuaternion1( copy([pQ[2] pQ[3] pQ[4]]) ,setQuaternionFromEuler(copy(rot)) )\n", " return [1.0 v[1] v[2] v[3]]\n", " # return [1.0 v[1] v[2] v[3]]\n", "end\n", "#transforms a vec3D in the original orientation of the bond to that as if the bond was in +X direction\n" ] }, { "cell_type": "code", "execution_count": 160, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "FromRotationVector (generic function with 1 method)" ] }, "execution_count": 160, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function ToRotationVector(a) \n", "\tif (a[1] >= 1.0 || a[1] <= -1.0) \n", "\t\treturn [0 0 0]\n", " end\n", "\tsquareLength = 1.0-a[1]*a[1]; # because x*x + y*y + z*z + w*w = 1.0, but more susceptible to w noise (when \n", "\tSLTHRESH_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\n", " \n", "\tif (squareLength < SLTHRESH_ACOS2SQRT) # ???????\n", "\t\treturn [a[2] a[3] a[4]] *(2.0*sqrt((2-2*a[1])/squareLength)); # acos(w) = sqrt(2*(1-x)) for w close to 1. for w=0.001, error is 1.317e-6\n", "\telse \n", "\t\treturn [a[2] a[3] a[4]] * (2.0*acos(a[1])/sqrt(squareLength));\n", " end \n", "end \n", "# !< Returns a rotation vector representing this quaternion rotation. Adapted from http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/\n", "\n", "\n", "function FromRotationVector(VecIn)\n", " theta=VecIn/2.0\n", " thetaMag2=norm(theta)*norm(theta)\n", " DBL_EPSILONx24 =5.328e-15\n", " if thetaMag2*thetaMag2 < DBL_EPSILONx24\n", " qw=1.0 - 0.5*thetaMag2\n", "\t\ts=1.0 - thetaMag2 / 6.0\n", " else\n", " thetaMag = sqrt(thetaMag2)\n", "\t\tqw=cos(thetaMag)\n", "\t\ts=sin(thetaMag) / thetaMag\n", " end\n", " qx=theta[1]*s\n", " qy=theta[2]*s\n", " qz=theta[3]*s;\n", " \n", " return [qw qx qy qz]\n", "end\n" ] }, { "cell_type": "code", "execution_count": 161, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "FromAngleToPosX (generic function with 1 method)" ] }, "execution_count": 161, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function FromAngleToPosX(a, RotateFrom) #highly optimized at the expense of readability\n", " \n", " SMALL_ANGLE_RAD= 1.732e-2 # Angles less than this get small angle approximations. To get: Root solve atan(t)/t-1+MAX_ERROR_PERCENT. From: MAX_ERROR_PERCENT = (t-atan(t))/t \n", " SMALL_ANGLE_W =0.9999625 # quaternion W value corresponding to a SMALL_ANGLE_RAD. To calculate, cos(SMALL_ANGLE_RAD*0.5).\n", " W_THRESH_ACOS2SQRT= 0.9988 # Threshhold of w above which we can approximate acos(w) with sqrt(2-2w). To get: Root solve 1-sqrt(2-2wt)/acos(wt) - MAX_ERROR_PERCENT. From MAX_ERROR_PERCENT = (acos(wt)-sqrt(2-2wt))/acos(wt)\n", "\n", " \n", "\tif (RotateFrom[1]==0 && RotateFrom[2]==0 && RotateFrom[3]==0) \n", "\t\treturn 0 #leave off if it slows down too much!!\n", " end\n", "\n", " # Catch and handle small angle:\n", " YoverX = RotateFrom[2]/RotateFrom[1]\n", " ZoverX = RotateFrom[3]/RotateFrom[1]\n", " if (YoverX<SMALL_ANGLE_RAD && YoverX>-SMALL_ANGLE_RAD && ZoverX<SMALL_ANGLE_RAD && ZoverX>-SMALL_ANGLE_RAD) # ??? //Intercept small angle and zero angle\n", "\t\tax=0\n", "\t\tay=0.5*ZoverX\n", "\t\taz=-0.5*YoverX\n", " aw = 1+0.5*(-a[3]*a[3]-a[4]*a[4]) # w=sqrt(1-x*x-y*y), small angle sqrt(1+x) ~= 1+x/2 at x near zero.\n", " return [aw ax ay az]\n", " end\n", "\n", " # more accurate non-small angle:\n", " RotFromNorm = copy(RotateFrom)\n", " RotFromNorm=normalize(collect(Iterators.flatten(RotFromNorm))) # Normalize the input...\n", "\n", " theta = acos(RotFromNorm[1]) # because RotFromNorm is normalized, 1,0,0 is normalized, and A.B = |A||B|cos(theta) = cos(theta)\n", " if(theta >(π-DISCARD_ANGLE_RAD)) # ??????\n", " aw=0\n", "\t\tax=0\n", "\t\tay=1\n", "\t\taz=0\n", " return [aw ax ay az]\n", " end # 180 degree rotation (about y axis, since the vector must be pointing in -x direction\n", "\n", " AxisMagInv = 1.0/sqrt(RotFromNorm[3]*RotFromNorm[3]+RotFromNorm[2]*RotFromNorm[2])\n", " # Here theta is the angle, axis is RotFromNorm.Cross(Vec3D(1,0,0)) = Vec3D(0, RotFromNorm.z/AxisMagInv, -RotFromNorm.y/AxisMagInv), which is still normalized. (super rolled together)\n", " aa = 0.5*theta\n", " s = sin(a)\n", "\taw= cos(aa)\n", "\tax= 0\n", "\tay= RotFromNorm[3]*AxisMagInv*s\n", "\taz = -RotFromNorm[2]*AxisMagInv*s # angle axis function, reduced\n", "\treturn [aw ax ay az]\n", "\n", "end\n", " # !< Overwrites this quaternion with the calculated rotation that would transform the specified RotateFrom vector to point in the positve X direction. Note: function changes this quaternion. @param[in] RotateFrom An arbitrary direction vector. Does not need to be normalized.\n" ] }, { "cell_type": "code", "execution_count": 162, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "stress (generic function with 1 method)" ] }, "execution_count": 162, "metadata": {}, "output_type": "execute_result" } ], "source": [ " function axialStrain(positiveEnd)\n", "\t# strainRatio = pVPos->material()->E/pVNeg->material()->E;\n", "\tstrainRatio=1.0\n", "\treturn positiveEnd ? (2.0 *strain*strainRatio/(1.0+strainRatio)) : (2.0*strain/(1.0+strainRatio))\n", "end\n", "\n", "function updateStrain( axialStrain,E) # ?from where strain\n", "\tstrain = axialStrain # redundant?\n", "\tcurrentTransverseStrainSum=0.0 # ??? todo\n", " linear=true\n", " maxStrain=100000000000000000000;# ?? todo later change\n", "\tif linear\n", "\t\tif axialStrain > maxStrain\n", "\t\t\tmaxStrain = axialStrain # remember this maximum for easy reference\n", " end\n", "\t\treturn stress(axialStrain,E)\n", "\telse \n", "\t\tif (axialStrain > maxStrain) # if new territory on the stress/strain curve\n", "\t\t\tmaxStrain = axialStrain # remember this maximum for easy reference\n", "\t\t\treturnStress = stress(axialStrain,E) # ??currentTransverseStrainSum\n", "\t\t\tif (nu != 0.0) \n", "\t\t\t\tstrainOffset = maxStrain-stress(axialStrain,E)/(_eHat*(1-nu)) # precalculate strain offset for when we back off\n", "\t\t\telse \n", " strainOffset = maxStrain-returnStress/E # precalculate strain offset for when we back off\n", " end\n", "\t\telse # backed off a non-linear material, therefore in linear region.\n", "\t\t\trelativeStrain = axialStrain-strainOffset # treat the material as linear with a strain offset according to the maximum plastic deformation\n", " if (nu != 0.0) \n", "\t\t\t\treturnStress = stress(relativeStrain,E)\n", "\t\t\telse \n", "\t\t\t\treturnStress = E*relativeStrain\n", " end\n", " end\n", "\t\treturn returnStress\n", " end\n", "end\n", "\n", "function stress( strain , E ) #end,transverseStrainSum, forceLinear){\n", "\t# reference: http://www.colorado.edu/engineering/CAS/courses.d/Structures.d/IAST.Lect05.d/IAST.Lect05.pdf page 10\n", "\t# if (isFailed(strain)) return 0.0f; //if a failure point is set and exceeded, we've broken!\n", "\t# var E =setup.edges[0].stiffness; //todo change later to material ??\n", "\t# var E=1000000;//todo change later to material ??\n", "\t# var scaleFactor=1;\n", " return E*strain;\n", "\n", "\t# # if (strain <= strainData[1] || linear || forceLinear){ //for compression/first segment and linear materials (forced or otherwise), simple calculation\n", " \n", " # if (nu==0.0) return E*strain;\n", "\t\t# else return _eHat*((1-nu)*strain + nu*transverseStrainSum); \n", "\t\t# else return eHat()*((1-nu)*strain + nu*transverseStrainSum); \n", "\t# # }\n", "\n", "\t# //the non-linear feature with non-zero poissons ratio is currently experimental\n", "\t# int DataCount = modelDataPoints();\n", "\t# 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.\n", "\t# \tif (strain <= strainData[i] || i==DataCount-1){ //if in the segment ending with this point (or if this is the last point extrapolate out) \n", "\t# \t\tfloat Perc = (strain-strainData[i-1])/(strainData[i]-strainData[i-1]);\n", "\t# \t\tfloat basicStress = stressData[i-1] + Perc*(stressData[i]-stressData[i-1]);\n", "\t# \t\tif (nu==0.0f) return basicStress;\n", "\t# \t\telse { //accounting for volumetric effects\n", "\t# \t\t\tfloat modulus = (stressData[i]-stressData[i-1])/(strainData[i]-strainData[i-1]);\n", "\t# \t\t\tfloat modulusHat = modulus/((1-2*nu)*(1+nu));\n", "\t# \t\t\tfloat effectiveStrain = basicStress/modulus; //this is the strain at which a simple linear stress strain line would hit this point at the definied modulus\n", "\t# \t\t\tfloat effectiveTransverseStrainSum = transverseStrainSum*(effectiveStrain/strain);\n", "\t# \t\t\treturn modulusHat*((1-nu)*effectiveStrain + nu*effectiveTransverseStrainSum);\n", "\t# \t\t}\n", "\t# \t}\n", "\t# }\n", "\n", "\t# assert(false); //should never reach this point\n", "\t# return 0.0f;\n", "end \n" ] }, { "cell_type": "code", "execution_count": 163, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "ToEulerAngles (generic function with 1 method)" ] }, "execution_count": 163, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function ToEulerAngles(q) # TODO I THINK WRONG\n", " # roll (x-axis rotation)\n", " sinr_cosp = (2 * (q[1] * q[2] + q[3] * q[4]) )== -0.0 ? 0.0 : (2 * (q[1] * q[2] + q[3] * q[4]) )\n", " cosr_cosp = (1 - 2 * (q[2] * q[2] + q[3] * q[3]))== -0.0 ? 0.0 : (1 - 2 * (q[2] * q[2] + q[3] * q[3]))\n", " \n", " roll = atan(sinr_cosp, cosr_cosp)\n", " \n", "\n", " # pitch (y-axis rotation)\n", " sinp = 2 * (q[1] * q[3] - q[4] * q[2])\n", " if (abs(sinp) >= 1)\n", " pitch = copysign(π / 2, sinp) # use 90 degrees if out of range\n", " else\n", " pitch = asin(sinp)\n", " end\n", "\n", " # yaw (z-axis rotation)\n", " siny_cosp = 2 * (q[1] * q[4] + q[2] * q[3])\n", " cosy_cosp = 1 - 2 * (q[3] * q[3] + q[4] * q[4])\n", " yaw = atan(siny_cosp, cosy_cosp)\n", " \n", "\n", " return [roll pitch yaw]\n", "end\n", "# ToEulerAngles(Quat(1.0,1.0,1.0,1.0))" ] }, { "cell_type": "code", "execution_count": 164, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "timeStep (generic function with 1 method)" ] }, "execution_count": 164, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# http://klas-physics.googlecode.com/svn/trunk/src/general/Integrator.cpp (reference)\n", "function timeStep(dt,node,static,currentTimeStep)\n", "\tpreviousDt = dt\n", "\tlinMom=copy(N_linMom[node])\n", " angMom=copy(N_angMom[node])\n", " orient=copy(N_orient[node])\n", "\tpos=copy(N_currPosition[node])\n", " \n", " \n", "\tif (dt == 0.0) \n", "\t\treturn 0\n", " end\n", "\n", "\tif(all(N_restrained_degrees_of_freedom[node] .>=1))\n", "\t\t# pos = originalPosition() + ext->translation();\n", "\t\t# orient = ext->rotationQuat();\n", "\t\t# haltMotion();\n", "\t\t# # pos=copy(N_position[node])\n", "\t\t# # node.currPosition=pos.clone();\n", "\t\t# # linMom = new THREE.Vector3(0,0,0);\n", "\t\t# # angMom = new THREE.Vector3(0,0,0);\n", "\t\t# # node.displacement={x:0,y:0,z:0};\n", "\n", "\t\t# node.orient=orient.clone();\n", "\t\t# node.linMom=linMom.clone();\n", "\t\t# node.angMom=angMom.clone();\n", "\t\treturn 0\n", " end\n", " \n", "\n", "\t# Translation\n", "\tcurForce = force(node,static,currentTimeStep)\n", "\n", "\t# var fricForce = curForce.clone();\n", "\n", "\t# if (isFloorEnabled()) floorForce(dt, &curForce); //floor force needs dt to calculate threshold to \"stop\" a slow voxel into static friction.\n", "\n", "\t# fricForce = curForce - fricForce;\n", "\n", "\t# assert(!(curForce.x != curForce.x) || !(curForce.y != curForce.y) || !(curForce.z != curForce.z)); //assert non QNAN\n", "\tlinMom=linMom+curForce*dt\n", " \n", "\n", "\tmassInverse=8e-6 # todo ?? later change\n", "\ttranslate=linMom*(dt*massInverse) # ??massInverse\n", "\n", " # //\twe need to check for friction conditions here (after calculating the translation) and stop things accordingly\n", "\t# if (isFloorEnabled() && floorPenetration() >= 0){ //we must catch a slowing voxel here since it all boils down to needing access to the dt of this timestep.\n", "\t# \tdouble work = fricForce.x*translate.x + fricForce.y*translate.y; //F dot disp\n", "\t# \tdouble hKe = 0.5*mat->_massInverse*(linMom.x*linMom.x + linMom.y*linMom.y); //horizontal kinetic energy\n", "\n", "\t# \tif(hKe + work <= 0) setFloorStaticFriction(true); //this checks for a change of direction according to the work-energy principle\n", "\n", "\t# \tif (isFloorStaticFriction()){ //if we're in a state of static friction, zero out all horizontal motion\n", "\t# \t\tlinMom.x = linMom.y = 0;\n", "\t# \t\ttranslate.x = translate.y = 0;\n", "\t# \t}\n", "\t# }\n", "\t# else setFloorStaticFriction(false);\n", " pos=pos+translate\n", " \n", " \n", " N_currPosition[node]=copy(pos)\n", " N_displacement[node]=N_displacement[node]+translate\n", "\n", "\t# Rotation\n", "\tcurMoment = moment(node)\n", " angMom=angMom+curMoment*dt\n", " \n", "\n", " \n", "\tmomentInertiaInverse=1.0 # todo ?? later change\n", " # orient=orient.*FromRotationVector(copy(angMom)*(dt*momentInertiaInverse))\n", " \n", " temp=FromRotationVector(copy(angMom)*(dt*momentInertiaInverse))\n", " \n", " orient=[orient[1]*temp[1] orient[2]*temp[2] orient[3]*temp[3] orient[4]*temp[4]]\n", " \n", "\t# orient.multiply(FromRotationVector(angMom.clone().multiplyScalar((dt*momentInertiaInverse)))) # tupdate the orientation //momentInertiaInverse\n", "\n", " N_orient[node]=copy(orient)\n", " \n", "\t\n", "\teul = ToEulerAngles(orient) # TODO I THINK WRONG\n", " \n", " N_angle[node]=copy(eul)\n", "\n", " N_linMom[node]=copy(linMom)\n", " N_angMom[node]=copy(angMom)\n", " \n", " \n", "\t\n", "\t# if (ext){//?? todo fix \n", "\t# \tvar size = 1;//change\n", "\t# \tif (ext->isFixed(X_TRANSLATE)) {pos.x = ix*size + ext->translation().x; linMom.x=0;}\n", "\t# \tif (ext->isFixed(Y_TRANSLATE)) {pos.y = iy*size + ext->translation().y; linMom.y=0;}\n", "\t# \tif (ext->isFixed(Z_TRANSLATE)) {pos.z = iz*size + ext->translation().z; linMom.z=0;}\n", "\t# \tif (ext->isFixedAnyRotation()){ //if any rotation fixed, all are fixed\n", "\t# \t\tif (ext->isFixedAllRotation()){\n", "\t# \t\t\torient = ext->rotationQuat();\n", "\t# \t\t\tangMom = Vec3D<double>();\n", "\t# \t\t}\n", "\t# \t\telse { //partial fixes: slow!\n", "\t# \t\t\tVec3D<double> tmpRotVec = orient.ToRotationVector();\n", "\t# \t\t\tif (ext->isFixed(X_ROTATE)){ tmpRotVec.x=0; angMom.x=0;}\n", "\t# \t\t\tif (ext->isFixed(Y_ROTATE)){ tmpRotVec.y=0; angMom.y=0;}\n", "\t# \t\t\tif (ext->isFixed(Z_ROTATE)){ tmpRotVec.z=0; angMom.z=0;}\n", "\t# \t\t\torient.FromRotationVector(tmpRotVec);\n", "\t# \t\t}\n", "\t# \t}\n", "\t# }\n", "\n", "\t# poissonsStrainInvalid = true;\n", "end" ] }, { "cell_type": "code", "execution_count": 165, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "moment (generic function with 1 method)" ] }, "execution_count": 165, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function force(node,static,currentTimeStep) \n", "\t# forces from internal bonds\n", "\ttotalForce=[0 0 0]\n", "\t# new THREE.Vector3(node.force.x,node.force.y,node.force.z);\n", "\t# todo \n", " \n", " \n", " \n", "\ttotalForce=totalForce+N_intForce[node]\n", "\n", "\t# for (int i=0; i<6; i++){ \n", "\t# \tif (links[i]) totalForce += links[i]->force(isNegative((linkDirection)i)); # total force in LCS\n", "\t# }\n", "\ttotalForce = RotateVec3D(N_orient[node],totalForce); # from local to global coordinates\n", " \n", "\n", "\t# assert(!(totalForce.x != totalForce.x) || !(totalForce.y != totalForce.y) || !(totalForce.z != totalForce.z)); //assert non QNAN\n", "\n", "\t# other forces\n", "\tif(static)\n", " totalForce=totalForce+N_force[node]\n", "\t# }else if(currentTimeStep<50){\n", "\t# \ttotalForce.add(new THREE.Vector3(node.force.x,node.force.y,node.force.z));\n", "\telse\n", "\t\t# var ex=0.1;\n", "\t\t# if(node.force.y!=0){\n", "\t\t# \tvar f=400*Math.sin(currentTimeStep*ex);\n", "\t\t# \ttotalForce.add(new THREE.Vector3(0,f,0));\n", "\t\t\t\n", "\t\t# }\n", "\t\tx=N_position[node][3]\n", "\t\tt=currentTimeStep\n", "\t\twave=getForce(x,t)\n", " totalForce=totalForce+[0 wave 0]\t\t\n", " end\n", " \n", "\n", "\t# if (externalExists()) totalForce += external()->force(); //external forces\n", "\t# totalForce -= velocity()*mat->globalDampingTranslateC(); //global damping f-cv\n", "\t# totalForce.z += mat->gravityForce(); //gravity, according to f=mg\n", "\n", "\t# if (isCollisionsEnabled()){\n", "\t# \tfor (std::vector<CVX_Collision*>::iterator it=colWatch->begin(); it!=colWatch->end(); it++){\n", "\t# \t\ttotalForce -= (*it)->contactForce(this);\n", "\t# \t}\n", "\t# }\n", "\t# todo make internal forces 0 again\n", " N_intForce[node]=[0 0 0] # do i really need it?\n", " \n", "\t# node.force.x=0;\n", "\t# node.force.y=0;\n", "\t# node.force.z=0;\n", " \n", " \n", "\treturn totalForce\n", "end\n", "\n", "function moment(node) \n", "\t#moments from internal bonds\n", "\ttotalMoment=[0 0 0]\n", "\t# for (int i=0; i<6; i++){ \n", "\t# \tif (links[i]) totalMoment += links[i]->moment(isNegative((linkDirection)i)); //total force in LCS\n", "\t# }\n", "\n", " totalMoment=totalMoment+N_intMoment[node]\n", " \n", "\ttotalMoment = RotateVec3D(N_orient[node],totalMoment);\n", " \n", " totalMoment=totalMoment+N_moment[node]\n", "\n", "\t#other moments\n", "\t# if (externalExists()) totalMoment += external()->moment(); //external moments\n", "\t# totalMoment -= angularVelocity()*mat->globalDampingRotateC(); //global damping\n", "\t\n", " N_intMoment[node]=[0 0 0] # do i really need it?\n", " \n", "\treturn totalMoment\n", "end" ] }, { "cell_type": "code", "execution_count": 166, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "updateDataAndSave (generic function with 1 method)" ] }, "execution_count": 166, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function updateDataAndSave(setup,fileName)\n", " nodes = setup[\"nodes\"]\n", " edges = setup[\"edges\"]\n", " voxCount=size(nodes)[1]\n", " linkCount=size(edges)[1]\n", "\n", " i=1\n", "\tfor edge in edges\n", " edge[\"stress\"]=E_stress[i]\n", " i=i+1\n", "\n", " end\n", " \n", " \n", " i=1 \n", "\tfor node in nodes\n", " node[\"displacement\"][\"x\"]=N_displacement[i][1]\n", " node[\"displacement\"][\"y\"]=N_displacement[i][2]\n", " node[\"displacement\"][\"z\"]=N_displacement[i][3]\n", " \n", " node[\"angle\"][\"x\"]=N_angle[i][1]\n", " node[\"angle\"][\"y\"]=N_angle[i][2]\n", " node[\"angle\"][\"z\"]=N_angle[i][3]\n", " i=i+1\n", "\n", " end\n", " \n", " # pass data as a json string (how it shall be displayed in a file)\n", " stringdata = JSON.json(setup)\n", "\n", " # write the file with the stringdata variable information\n", " open(fileName, \"w\") do f\n", " write(f, stringdata)\n", " end\n", " \n", "end" ] }, { "cell_type": "code", "execution_count": 169, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Dict{String,Any} with 6 entries:\n", " \"nodes\" => Any[Dict{String,Any}(\"degrees_of_freedom\"=>Any[0, 1, 2, 3, 4, …\n", " \"bar\" => false\n", " \"animation\" => Dict{String,Any}(\"speed\"=>3,\"exaggeration\"=>100,\"showDisplaceme…\n", " \"viz\" => Dict{String,Any}(\"colorMap\"=>0,\"colorMaps\"=>Any[],\"maxStress\"=…\n", " \"edges\" => Any[Dict{String,Any}(\"currentRestLength\"=>0,\"source\"=>0,\"area\"…\n", " \"ndofs\" => 18" ] }, "execution_count": 169, "metadata": {}, "output_type": "execute_result" } ], "source": [ "setup = Dict()\n", "open(\"../json/setupValid2.json\", \"r\") do f\n", " global setup\n", " dicttxt = String(read(f)) # file information to string\n", " setup=JSON.parse(dicttxt) # parse and transform data\n", "end\n", "\n", "setup=setup[\"setup\"]" ] }, { "cell_type": "code", "execution_count": 173, "metadata": {}, "outputs": [ { "ename": "BoundsError", "evalue": "BoundsError", "output_type": "error", "traceback": [ "BoundsError", "", "Stacktrace:", " [1] getindex at .\\number.jl:78 [inlined]", " [2] RotateVec3D(::Array{Float64,2}, ::Array{Float64,2}) at .\\In[154]:13", " [3] orientLink(::Int64) at .\\In[172]:13", " [4] updateForces(::Dict{String,Any}, ::Int64, ::Bool) at .\\In[152]:25", " [5] doTimeStep(::Dict{String,Any}, ::Float64, ::Bool, ::Int64, ::Int64) at .\\In[151]:27", " [6] simulateParallel(::Dict{String,Any}, ::Int64, ::Float64, ::Bool, ::Int64) at .\\In[149]:5", " [7] top-level scope at util.jl:289", " [8] top-level scope at In[173]:50" ] } ], "source": [ "\n", "\n", "\n", "############# nodes\n", "N_position=[]\n", "N_degrees_of_freedom=[]\n", "N_restrained_degrees_of_freedom=[]\n", "N_displacement=[]\n", "N_angle=[]\n", "N_currPosition=[]\n", "N_linMom=[]\n", "N_angMom=[]\n", "N_intForce=[]\n", "N_intMoment=[]\n", "N_moment=[]\n", "N_posTimeSteps=[]\n", "N_angTimeSteps=[]\n", "N_force=[]\n", "N_orient=[]\n", "\n", "############# edges\n", "E_source=[]\n", "E_target=[]\n", "E_area=[]\n", "E_density=[]\n", "E_stiffness=[]\n", "E_stress=[]\n", "E_axis=[]\n", "E_currentRestLength=[]\n", "E_pos2=[]\n", "E_angle1v=[]\n", "E_angle2v=[]\n", "E_angle1=[]\n", "E_angle2=[]\n", "E_currentTransverseStrainSum=[]\n", "E_stressTimeSteps=[]\n", "\n", "########\n", "voxCount=0\n", "linkCount=0\n", "nodes = setup[\"nodes\"]\n", "edges = setup[\"edges\"]\n", "voxCount=size(nodes)[1]\n", "linkCount=size(edges)[1]\n", "strain =0 #todooo moveeee\n", "\n", "dt=0.0251646\n", "numTimeSteps =1\n", "latticeSize =1\n", "t=@timed simulateParallel(setup,numTimeSteps,dt,true,10)\n", "time=t[2]\n", "println(\"ran latticeSize $latticeSize with $voxCount voxels and $linkCount edges for $numTimeSteps time steps took $time seconds\")\n", "N_displacement" ] }, { "cell_type": "code", "execution_count": 171, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "4486" ] }, "execution_count": 171, "metadata": {}, "output_type": "execute_result" } ], "source": [ "save=true\n", "if save\n", " updateDataAndSave(setup,\"../json/trialJuliaParallel.json\")\n", "end" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Julia 1.2.0", "language": "julia", "name": "julia-1.2" }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", "version": "1.2.0" } }, "nbformat": 4, "nbformat_minor": 4 }