{ "cells": [ { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "using LinearAlgebra\n", "using Plots\n", "import JSON" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "points (generic function with 1 method)" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function points(element, properties)\n", " elements = properties[\"elements\"]\n", " nodes = properties[\"nodes\"]\n", " degrees_of_freedom = properties[\"degrees_of_freedom\"]\n", " \n", "\t# find the nodes that the lements connects\n", "\tfromNode = elements[element][1]\n", "\ttoNode = elements[element][2]\n", "\n", "\t# the coordinates for each node\n", "\tfromPoint = nodes[fromNode]\n", "\ttoPoint = nodes[toNode]\n", "\n", "\t# find the degrees of freedom for each node\n", "\tdofs = degrees_of_freedom[fromNode]\n", " dofs=vcat(dofs,degrees_of_freedom[toNode])\n", "\n", "\treturn fromPoint, toPoint, dofs\n", "end" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "rotation_matrix (generic function with 1 method)" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function direction_cosine(vec1, vec2)\n", " return dot(vec1,vec2) / (norm(vec1) * norm(vec2))\n", "end\n", "\n", "function rotation_matrix(element_vector, x_axis, y_axis,z_axis)\n", " # find the direction cosines\n", "\tx_proj = direction_cosine(element_vector, x_axis)\n", "\ty_proj = direction_cosine(element_vector, y_axis)\n", " z_proj = direction_cosine(element_vector, z_axis);\n", "\treturn [[x_proj y_proj z_proj 0 0 0];[0 0 0 x_proj y_proj z_proj]]\n", "end\n", "\n", "function rotation_matrix(element_vector, x_axis, y_axis,z_axis)\n", " # find the direction cosines\n", " L=norm(element_vector)\n", " l = (element_vector[1])/L\n", "\tm = (element_vector[2])/L\n", "\tn = (element_vector[3])/L\n", "\tD = ( l^2+ m^2+n^2)^0.5\n", " \n", " transMatrix=[[l m n 0 0 0 0 0 0 0 0 0];[-m/D l/D 0 0 0 0 0 0 0 0 0 0];[ -l*n/D -m*n/D D 0 0 0 0 0 0 0 0 0];[ 0 0 0 l m n 0 0 0 0 0 0];[ 0 0 0 -m/D l/D 0 0 0 0 0 0 0];[ 0 0 0 -l*n/D -m*n/D D 0 0 0 0 0 0];[ 0 0 0 0 0 0 l m n 0 0 0];[ 0 0 0 0 0 0 -m/D l/D 0 0 0 0];[ 0 0 0 0 0 0 -l*n/D -m*n/D D 0 0 0];[ 0 0 0 0 0 0 0 0 0 l m n];[ 0 0 0 0 0 0 0 0 0 -m/D l/D 0];[ 0 0 0 0 0 0 0 0 0 -l*n/D -m*n/D D]]\n", "\t\n", " return transMatrix\n", "end" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "get_stresses1 (generic function with 1 method)" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function get_matrices1(setup)\n", " # cosntruct the global mass and stifness matrices\n", " ndofs = setup[\"ndofs\"]\n", " nodes = setup[\"nodes\"]\n", " edges = setup[\"edges\"]\n", "\n", " x_axis = [1 0 0]\n", " y_axis = [0 1 0]\n", " z_axis = [0 0 1]\n", " \n", " M = zeros((ndofs,ndofs))\n", " K = zeros((ndofs,ndofs))\n", " \n", " for edge in edges\n", " #degrees_of_freedom = properties[\"degrees_of_freedom\"]\n", "\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", " # the coordinates for each node\n", " fromPoint = [fromNode[\"position\"][\"x\"] fromNode[\"position\"][\"y\"] fromNode[\"position\"][\"z\"]]\n", " toPoint = [toNode[\"position\"][\"x\"] toNode[\"position\"][\"y\"] toNode[\"position\"][\"z\"]]\n", "\n", " # find the degrees of freedom for each node\n", " dofs = convert(Array{Int}, fromNode[\"degrees_of_freedom\"])\n", " dofs=vcat(dofs,convert(Array{Int}, toNode[\"degrees_of_freedom\"]))\n", "\n", " element_vector=toPoint-fromPoint\n", "\n", " # find element mass and stifness matrices\n", " length = norm(element_vector)\n", " rho = edge[\"density\"]\n", " area = edge[\"area\"]\n", " E = edge[\"stiffness\"]# youngs modulus\n", "\n", " Cm = rho * area * length /6.0\n", " Ck= E * area / length \n", "\n", " m = [[2 1];[1 2]]\n", " k = [[1 -1];[-1 1]]\n", "\n", " # find rotated mass and stifness matrices\n", " tau = rotation_matrix(element_vector, x_axis,y_axis,z_axis)\n", " \n", " m_r=transpose(tau)*m*tau\n", " k_r=transpose(tau)*k*tau\n", " \n", " \n", " # change from element to global coordinate\n", " index= dofs.+1\n", "\n", " B=zeros((6,ndofs))\n", " for i in 1:6\n", " B[i,index[i]]=1.0\n", " end\n", " \n", " \n", " \n", " M_rG= transpose(B)*m_r*B\n", " K_rG= transpose(B)*k_r*B\n", " \n", "\n", " M += Cm .* M_rG\n", " K += Ck .* K_rG\n", " \n", " end\n", "\n", " # construct the force vector\n", " F=zeros(ndofs)\n", " remove_indices=[];\n", " for node in nodes\n", " #insert!(F,i, value);\n", " #F=vcat(F,value)\n", " i=parse(Int,node[\"id\"][2:end])+1\n", " F[(i-1)*3+1]=value[1] \n", " F[(i-1)*3+2]=value[2]\n", " F[(i-1)*3+3]=value[3]\n", " dofs = convert(Array{Int}, node[\"degrees_of_freedom\"])+1\n", " restrained_dofs=node[\"restrained_dofs\"]\n", " for (index, value) in enumerate(dofs)\n", " if restrained_dofs[index]\n", " append!( remove_indices, value)\n", " end\n", " end\n", " end\n", " \n", " \n", " # remove the restrained dofs\n", "# remove_indices=setup[\"restrained_dofs\"]\n", " \n", " \n", " # print(M)\n", " # print(K)\n", " # print(F)\n", " \n", "\n", " M = M[setdiff(1:end, remove_indices), :]\n", " K = K[setdiff(1:end, remove_indices), :]\n", "\n", " M = M[:,setdiff(1:end, remove_indices)]\n", " K = K[:,setdiff(1:end, remove_indices)]\n", " \n", " F = F[setdiff(1:end, remove_indices)]\n", "\n", " return M,K,F\n", " \n", "end\n", "function get_stresses1(setup,X)\n", " \n", " elements = properties[\"elements\"]\n", " \n", " ndofs = setup[\"ndofs\"]\n", " nodes = setup[\"nodes\"]\n", " edges = setup[\"edges\"]\n", "\n", " x_axis = [1 0 0]\n", " y_axis = [0 1 0]\n", " z_axis = [0 0 1]\n", "\n", " # find the stresses in each member\n", " stresses=zeros(length(edges))\n", " for edge in edges\n", " #degrees_of_freedom = properties[\"degrees_of_freedom\"]\n", "\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", " # the coordinates for each node\n", " fromPoint = [fromNode[\"position\"][\"x\"] fromNode[\"position\"][\"y\"] fromNode[\"position\"][\"z\"]]\n", " toPoint = [toNode[\"position\"][\"x\"] toNode[\"position\"][\"y\"] toNode[\"position\"][\"z\"]]\n", "\n", " # find the degrees of freedom for each node\n", " dofs = convert(Array{Int}, fromNode[\"degrees_of_freedom\"])\n", " dofs=vcat(dofs,convert(Array{Int}, toNode[\"degrees_of_freedom\"]))\n", "\n", " element_vector=toPoint-fromPoint\n", " \n", "\n", " # find rotated mass and stifness matrices\n", " tau = rotation_matrix(element_vector, x_axis,y_axis,z_axis)\n", " global_displacements=[X[1] X[2] X[3] X[1] X[2] X[3]] # todo change\n", " # nodal displacement\n", "\n", " q=tau*transpose(global_displacements)\n", " # println(q)\n", " # calculate the strain and stresses\n", " strain =(q[2]-q[1])/norm(element_vector)\n", " stress=E[element].*strain\n", " # println(element)\n", " # println(stress)\n", " stresses[element]=stress\n", " end\n", " return stresses\n", "end\n", "\n" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "get_stresses (generic function with 1 method)" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function get_stresses(setup)\n", " nodes = setup[\"nodes\"]\n", " edges = setup[\"edges\"]\n", " ndofs = length(nodes)*6\n", "\n", " x_axis = [1 0 0]\n", " y_axis = [0 1 0]\n", " z_axis = [0 0 1]\n", "\n", " # find the stresses in each member\n", " stresses=zeros(length(edges))\n", " max11=-10e6\n", " min11=10e6\n", " for edge in edges\n", " #degrees_of_freedom = properties[\"degrees_of_freedom\"]\n", "\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", " # the coordinates for each node\n", " fromPoint = [fromNode[\"position\"][\"x\"] fromNode[\"position\"][\"y\"] fromNode[\"position\"][\"z\"]]\n", " toPoint = [toNode[\"position\"][\"x\"] toNode[\"position\"][\"y\"] toNode[\"position\"][\"z\"]]\n", "\n", " # find the degrees of freedom for each node\n", " dofs = convert(Array{Int}, fromNode[\"degrees_of_freedom\"])\n", " dofs=vcat(dofs,convert(Array{Int}, toNode[\"degrees_of_freedom\"]))\n", "\n", " element_vector=toPoint-fromPoint\n", " \n", "\n", " # find rotated mass and stifness matrices\n", " tau = rotation_matrix(element_vector, x_axis,y_axis,z_axis)\n", " \n", " # i1=parse(Int,fromNode[\"id\"][2:end])\n", " # i2=parse(Int,toNode[\"id\"][2:end])\n", " \n", " # global_displacements=[X[(i1)*6+1] X[(i1)*6+2] X[(i1)*6+3] X[(i1)*6+4] X[(i1)*6+5] X[(i1)*6+6] X[(i2)*6+1] X[(i2)*6+2] X[(i2)*6+3] X[(i2)*6+4] X[(i2)*6+5] X[(i2)*6+6]] # todo change\n", " global_displacements=[fromNode[\"displacement\"][\"x\"] fromNode[\"displacement\"][\"y\"] fromNode[\"displacement\"][\"z\"] fromNode[\"angle\"][\"x\"] fromNode[\"angle\"][\"y\"] fromNode[\"angle\"][\"z\"] toNode[\"displacement\"][\"x\"] toNode[\"displacement\"][\"y\"] toNode[\"displacement\"][\"z\"] toNode[\"angle\"][\"x\"] toNode[\"angle\"][\"y\"] toNode[\"angle\"][\"z\"]] # todo change\n", "\n", " # nodal displacement\n", "\n", " q=tau*transpose(global_displacements)\n", " # println(q)\n", " # calculate the strain and stresses\n", " strain =(q[7]-q[1])/norm(element_vector)\n", " E = edge[\"stiffness\"]# youngs modulus\n", " stress=E.*strain\n", " edge[\"stress\"]=stress\n", " if stress>max11\n", " max11=stress\n", " end\n", " if stress<min11\n", " min11=stress\n", " end\n", " # println(element)\n", " # println(stress)\n", " end\n", "\n", " \n", " \n", " setup[\"viz\"][\"minStress\"]=min11\n", " setup[\"viz\"][\"maxStress\"]=max11\n", " return stresses\n", "end" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Dict{String,Any} with 8 entries:\n", " \"nodes\" => Any[Dict{String,Any}(\"degrees_of_freedom\"=>Any[0, 1, 2, 3, …\n", " \"voxelSize\" => 5\n", " \"numTimeSteps\" => 100\n", " \"hierarchical\" => false\n", " \"animation\" => Dict{String,Any}(\"speed\"=>3,\"exaggeration\"=>2000,\"showDispla…\n", " \"viz\" => Dict{String,Any}(\"colorMap\"=>0,\"colorMaps\"=>Any[Any[Any[0, …\n", " \"edges\" => Any[Dict{String,Any}(\"source\"=>0,\"area\"=>1,\"density\"=>0.028…\n", " \"ndofs\" => 324" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "###################\n", "### Read data #####\n", "###################\n", "###############################################################################################\n", "latticeSize =2\n", "setup = Dict()\n", "name=string(\"../json/setupTestUni$latticeSize\",\".json\")\n", "open(name, \"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", "# println(setup[\"viz\"][\"minStress\"])\n", "setup=setup[\"setup\"]\n", "# printls(setup.viz)" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "get_matrices (generic function with 1 method)" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function get_matrices(setup)\n", "\n", " nodes = setup[\"nodes\"]\n", " edges = setup[\"edges\"]\n", " ndofs = length(nodes)*6\n", "\n", " x_axis = [1 0 0]\n", " y_axis = [0 1 0]\n", " z_axis = [0 0 1]\n", "\n", " M = zeros((ndofs,ndofs))\n", " K = zeros((ndofs,ndofs))\n", "\n", " for edge in edges\n", " #degrees_of_freedom = properties[\"degrees_of_freedom\"]\n", "\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", " # the coordinates for each node\n", " fromPoint = [fromNode[\"position\"][\"x\"] fromNode[\"position\"][\"y\"] fromNode[\"position\"][\"z\"]]\n", " toPoint = [toNode[\"position\"][\"x\"] toNode[\"position\"][\"y\"] toNode[\"position\"][\"z\"]]\n", "\n", " # find the degrees of freedom for each node\n", " dofs = convert(Array{Int}, fromNode[\"degrees_of_freedom\"])\n", " dofs=vcat(dofs,convert(Array{Int}, toNode[\"degrees_of_freedom\"]))\n", "\n", " element_vector=toPoint-fromPoint\n", "\n", " # find element mass and stifness matrices\n", " length = norm(element_vector)\n", " rho = edge[\"density\"]\n", " area = edge[\"area\"]\n", " E = edge[\"stiffness\"]# youngs modulus\n", "\n", " A = edge[\"area\"]\n", " G=1.0#todo shear_modulus\n", " ixx = 1.0#todo section ixx\n", " iyy = 1.0#todo section.iyy#\n", " l0=length\n", " j=1.0;#todo check\n", " l02 = l0 * l0\n", " l03 = l0 * l0 * l0\n", "\n", " # Cm = rho * area * length /6.0\n", " # Ck= E * area / length \n", "\n", " # m = [[2 1];[1 2]]\n", " # k = [[1 -1];[-1 1]]\n", "\n", " k = [[E*A/l0 0 0 0 0 0 -E*A/l0 0 0 0 0 0];[0 12*E*ixx/l03 0 0 0 6*E*ixx/l02 0 -12*E*ixx/l03 0 0 0 6*E*ixx/l02];[0 0 12*E*iyy/l03 0 -6*E*iyy/l02 0 0 0 -12*E*iyy/l03 0 -6*E*iyy/l02 0];[0 0 0 G*j/l0 0 0 0 0 0 -G*j/l0 0 0];[0 0 -6*E*iyy/l02 0 4*E*iyy/l0 0 0 0 6*E*iyy/l02 0 2*E*iyy/l0 0];[0 6*E*ixx/l02 0 0 0 4*E*ixx/l0 0 -6*E*ixx/l02 0 0 0 2*E*ixx/l0];[-E*A/l0 0 0 0 0 0 E*A/l0 0 0 0 0 0];[0 -12*E*ixx/l03 0 0 0 -6*E*ixx/l02 0 12*E*ixx/l03 0 0 0 -6*E*ixx/l02];[0 0 -12*E*iyy/l03 0 6*E*iyy/l02 0 0 0 12*E*iyy/l03 0 6*E*iyy/l02 0];[0 0 0 -G*j/l0 0 0 0 0 0 G*j/l0 0 0];[0 0 -6*E*iyy/l02 0 2*E*iyy/l0 0 0 0 6*E*iyy/l02 0 4*E*iyy/l0 0];[0 6*E*ixx/l02 0 0 0 2*E*ixx/l0 0 -6*E*ixx/l02 0 0 0 4*E*ixx/l0]]\n", "\n", " # find rotated mass and stifness matrices\n", " tau = rotation_matrix(element_vector, x_axis,y_axis,z_axis)\n", "\n", " # m_r=transpose(tau)*m*tau\n", " k_r=transpose(tau)*k*tau\n", "\n", "\n", " # change from element to global coordinate\n", " index= dofs.+1\n", "\n", " B=zeros((12,ndofs))\n", " for i in 1:12\n", " B[i,index[i]]=1.0\n", " end\n", "\n", "\n", " # M_rG= transpose(B)*m_r*B\n", " K_rG= transpose(B)*k_r*B\n", "\n", " # M += Cm .* M_rG\n", " # K += Ck .* K_rG\n", " K += K_rG\n", "\n", " end\n", "\n", " # construct the force vector\n", " F=zeros(ndofs)\n", " remove_indices=[];\n", " for node in nodes\n", " #insert!(F,i, value);\n", " #F=vcat(F,value)\n", " i=parse(Int,node[\"id\"][2:end])\n", " f=node[\"force\"]\n", " # println(f)\n", " F[(i)*6+1]=f[\"x\"]\n", " F[(i)*6+2]=f[\"y\"]\n", " F[(i)*6+3]=f[\"z\"]\n", " F[(i)*6+4]=0\n", " F[(i)*6+5]=0\n", " F[(i)*6+6]=0\n", " dofs = convert(Array{Int}, node[\"degrees_of_freedom\"]).+1\n", " restrained_dofs=node[\"restrained_degrees_of_freedom\"]\n", " for (index, value) in enumerate(dofs)\n", " if restrained_dofs[index]\n", " append!( remove_indices, value)\n", " end\n", " end\n", " end\n", "\n", "# println(remove_indices)\n", "# print(K)\n", "# print(F)\n", "\n", "# M = M[setdiff(1:end, remove_indices), :]\n", " K = K[setdiff(1:end, remove_indices), :]\n", "\n", "# M = M[:,setdiff(1:end, remove_indices)]\n", " K = K[:,setdiff(1:end, remove_indices)]\n", "\n", " F = F[setdiff(1:end, remove_indices)]\n", " return M,K,F\n", "end" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "updateDisplacement (generic function with 1 method)" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function updateDisplacement(setup, X)\n", " nodes= setup[\"nodes\"]\n", " i=0\n", " for node in nodes\n", " if !node[\"restrained_degrees_of_freedom\"][1]\n", "# #i=parse(Int,node[\"id\"][2:end])\n", " node[\"displacement\"][\"x\"]=X[(i)*6+1]\n", " node[\"displacement\"][\"y\"]=X[(i)*6+2]\n", " node[\"displacement\"][\"z\"]=X[(i)*6+3]\n", " node[\"angle\"][\"x\"]=X[(i)*6+4]\n", " node[\"angle\"][\"y\"]=X[(i)*6+5]\n", " node[\"angle\"][\"z\"]=X[(i)*6+6]\n", " i=i+1\n", " end\n", " end\n", "end\n", "\n" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "144-element Array{Float64,1}:\n", " 0.0\n", " 0.0\n", " 0.0\n", " 0.0\n", " 0.0\n", " 0.0\n", " 0.0\n", " 0.0\n", " 0.0\n", " 0.0\n", " 0.0\n", " 0.0\n", " 0.0\n", " ⋮ \n", " 0.0\n", " 0.0\n", " 0.0\n", " 0.0\n", " 0.0\n", " 0.0\n", " 0.0\n", " 0.0\n", " 0.0\n", " 0.0\n", " 0.0\n", " 0.0" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function solveFea(setup)\n", "\t// # determine the global matrices\n", "\tM,K,F=get_matrices(setup)\n", " \n", " #println(M)\n", " #println(K)\n", " #println(F)\n", " \n", " #evals=eigvals(K,M)\n", " #evecs=eigvecs(K,M)\n", " #frequencies=sqrt.(evals)\n", " X=inv(K)*F\n", " # println(X)\n", " \n", " \n", " #updateDisplacement(displacements);\n", " updateDisplacement(setup, X)\n", " \n", " # determine the stresses in each element\n", " stresses=get_stresses(setup)\n", "\n", "end\n", "solveFea(setup)\n" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "86709" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 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(\"../json/trialJuliaParallelGPU.json\", \"w\") do f\n", " write(f, stringdata)\n", " end" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "-15.254698203231039" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "setup[\"viz\"][\"minStress\"]" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "ename": "UndefVarError", "evalue": "UndefVarError: val not defined", "output_type": "error", "traceback": [ "UndefVarError: val not defined", "", "Stacktrace:", " [1] top-level scope at In[13]:1" ] } ], "source": [ "# print(\"Pi: {0}, Time: {1}, MFlops: {2}\".format(val, sec, mflops))\n", "# print(\"This calculation happened in Javascript\")\n", "println(val)\n", "println(sec)\n", "println(mflops)" ] }, { "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": 2 }