1+ using JSON
2+ using Fire
3+ using Gmsh
4+ using ExtendableGrids
5+ using ExtendableFEM
6+ using StaticArrays: @SArray
7+ using Unitful
8+ using LinearAlgebra
9+ using ZipArchives: ZipWriter, zip_newfile
10+
11+ struct PlateConfig
12+ id:: String
13+ F:: Float64
14+ E:: Float64
15+ ν:: Float64
16+ radius:: Float64
17+ length:: Float64
18+ element_order:: Int64
19+ end
20+
21+ struct Metrics
22+ max_von_mises_stress_nodes:: Float64
23+ end
24+
25+ function value_with_unit (json:: JSON.Object{String,Any} )
26+ res = uparse (string (json[" value" ])* json[" unit" ])
27+ return res
28+ end
29+
30+
31+ function parse_config (configfile:: String )
32+ config = JSON. parsefile (configfile)
33+ id = config[" configuration" ]
34+ F = ustrip (u " Pa" ,value_with_unit (config[" load" ]))
35+ E = ustrip (u " Pa" ,value_with_unit (config[" young-modulus" ]))
36+ ν = config[" poisson-ratio" ][" value" ]
37+ radius = ustrip (u " m" ,value_with_unit (config[" radius" ]))
38+ length = ustrip (u " m" ,value_with_unit (config[" length" ]))
39+ element_order = config[" element-order" ]
40+ return PlateConfig (id,F,E,ν,radius,length,element_order)
41+ end
42+
43+
44+ function plane_stress_elasticity_tensor (E:: Float64 , ν:: Float64 )
45+ G = (1 / (1 + ν)) * E * 0.5
46+ λ = (ν / (1 - 2 ν)) * 2 * G
47+ return @SArray [
48+ (λ + 2 G) λ 0
49+ λ (λ + 2 G) 0
50+ 0 0 G
51+ ]
52+ end
53+
54+
55+ function make_kernel (𝐂)
56+ function LE_kernel_sym! (σ,εv,qpinfo)
57+ mul! (σ,𝐂,εv)
58+ end
59+ return LE_kernel_sym!
60+ end
61+
62+ function u_ex_kernel! (result,qpinfo)
63+ x = qpinfo. x[1 ]
64+ y = qpinfo. x[2 ]
65+ a = qpinfo. params[1 ]
66+ T = qpinfo. params[2 ]
67+ E = qpinfo. params[3 ]
68+ ν = qpinfo. params[4 ]
69+ r = sqrt (x^ 2 + y^ 2 )
70+ θ = atan (y,x)
71+ k = (3.0 - ν)/ (1.0 + ν)
72+ Ta_8mu = T* a* (1.0 + ν)/ (4.0 * E)
73+ ct = cos (θ)
74+ c3t = cos (3.0 * θ)
75+ st = sin (θ)
76+ s3t = sin (3.0 * θ)
77+ fac = 2.0 * (a/ r)^ 3
78+
79+
80+ result[1 ] = Ta_8mu * (
81+ (r/ a) * (k + 1.0 ) * ct
82+ + 2.0 * (a/ r)* ((1.0 + k) * ct + c3t)
83+ - fac * c3t
84+ )
85+ result[2 ] = Ta_8mu * (
86+ (r/ a) * (k - 3.0 ) * st
87+ + 2.0 * (a/ r)* ((1.0 - k) * st + s3t)
88+ - fac * s3t
89+ )
90+ end
91+
92+ function exact_error! (result,u, qpinfo)
93+ u_ex_kernel! (result,qpinfo)
94+ result .- = u
95+ result .= result .^ 2
96+ return nothing
97+ end
98+
99+ function solve_plate_with_hole (config:: PlateConfig ,grid:: ExtendableGrid ,outputzip:: String ,outputmetrics:: String )
100+
101+ bfacemask! (grid,[0. ,0. ],[config. radius,config. radius],50 )
102+
103+ PD = ProblemDescription (" Linear elastic 2D Plate with hole, configuration " * config. id)
104+ u = Unknown (" u" ; name= " displacement" )
105+ assign_unknown! (PD, u)
106+ 𝐂 = plane_stress_elasticity_tensor (config. E,config. ν)
107+ LE_kernel_sym! = make_kernel (𝐂)
108+ assign_operator! (PD, BilinearOperator (LE_kernel_sym!, [εV (u,1.0 )]))
109+ assign_operator! (PD, InterpolateBoundaryData (u, u_ex_kernel!; regions = [3 ,4 ], params = [config. radius,config. F,config. E,config. ν]))
110+ assign_operator! (PD, HomogeneousBoundaryData (u; regions = [1 ], mask = [1 ,0 ]))
111+ assign_operator! (PD, HomogeneousBoundaryData (u; regions = [2 ], mask = [0 ,1 ]))
112+
113+ FEType = H1Pk{2 ,2 , config. element_order}
114+ FES = FESpace {FEType} (grid)
115+ sol = solve (PD,FES; timeroutputs = :hide )
116+
117+ u_ex = FEVector (FES; name= " exact solution" )
118+ interpolate! (u_ex. FEVectorBlocks[1 ],ON_CELLS,u_ex_kernel!;params = [config. radius,config. F,config. E,config. ν])
119+ u_exx = nodevalues (u_ex. FEVectorBlocks[1 ])[1 ,:]
120+ u_exy = nodevalues (u_ex. FEVectorBlocks[1 ])[2 ,:]
121+
122+ u_x = nodevalues (sol[u])[1 ,:]
123+ u_y = nodevalues (sol[u])[2 ,:]
124+ u_mag = sqrt .(u_x.* u_x.+ u_y.* u_y)
125+ uex_mag = sqrt .(u_exx.* u_exx.+ u_exy.* u_exy)
126+
127+ # TODO : Stress calculations
128+
129+ metrics = Metrics (0. )
130+ # TODO : L2 error, see Example301
131+ ErrorIntegrationExact = ItemIntegrator (exact_error!, [id (u)]; quadorder = 8 ,params = [config. radius,config. F,config. E,config. ν])
132+
133+ error = evaluate (ErrorIntegrationExact, sol)
134+
135+ L2error = sqrt (sum (error))
136+
137+ outputvtk = splitdir (outputzip)[1 ]* " /results_" * config. id* " .vtu" ;
138+ writeVTK (outputvtk,grid;compress= false , u_x= u_x,u_y= u_y,u_mag= u_mag,uexx= u_exx,uexy= u_exy,uex= uex_mag)
139+ f = open (outputvtk," r" )
140+ vtkcontent = read (f,String)
141+ ZipWriter (outputzip) do w
142+ zip_newfile (w, " result_" * config. id* " .vtu" ;compress= true )
143+ write (w,vtkcontent)
144+ end
145+ JSON. json (outputmetrics,metrics;pretty= true )
146+
147+ end
148+
149+ " run linear elastic plate with a hole using ExtendableFEM.jl"
150+ Fire. @main function run_simulation (;
151+ configfile:: String = " " ,
152+ meshfile:: String = " " ,
153+ outputzip:: String = " " ,
154+ outputmetrics:: String = " "
155+ )
156+ if (isempty (configfile))
157+ @error " No configuration file given"
158+ end
159+ config = parse_config (configfile)
160+ if (isempty (meshfile))
161+ @error " No mesh file given"
162+ end
163+ if (isempty (outputzip))
164+ @error " No output zip file given"
165+ end
166+ if (isempty (outputmetrics))
167+ @error " No output metrics file given"
168+ end
169+ grid = simplexgrid_from_gmsh (meshfile)
170+ solve_plate_with_hole (config,grid,outputzip,outputmetrics)
171+
172+ return
173+ end
0 commit comments