convergence.jl 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. # using Revise
  2. using Flower
  3. using YAML
  4. using Printf
  5. # ---------------------------------------------------------------------------------------------
  6. # FUNCTION BARRIER: Wrapper pour exécuter la simulation
  7. # Cela permet d'isoler le code compilé des variables dynamiques (BC) générées par eval()
  8. # ---------------------------------------------------------------------------------------------
  9. function execute_simulation_step(num, gp, gu, gv, op, phS, phL, sim, phys, time_scheme, bc_dict)
  10. # Préparation des arguments optionnels (Keyword Arguments)
  11. # On construit un NamedTuple uniquement avec les BC qui existent vraiment
  12. kwargs_bc = Dict{Symbol, Any}()
  13. # Liste des clés possibles
  14. keys_to_check = [:BC_uL, :BC_uS, :BC_vL, :BC_vS, :BC_pL, :BC_pS, :BC_u, :BC_int, :BC_trans_scal, :BC_phi_ele]
  15. for k in keys_to_check
  16. if haskey(bc_dict, k)
  17. kwargs_bc[k] = bc_dict[k]
  18. end
  19. end
  20. # Appel avec le splatting operator (...) qui déballe le dictionnaire en arguments
  21. run_forward!(
  22. num, gp, gu, gv, op, phS, phL;
  23. periodic_x = (sim.periodic_x == 1),
  24. periodic_y = (sim.periodic_y == 1),
  25. auto_reinit = sim.auto_reinit,
  26. time_scheme = time_scheme,
  27. electrolysis = true,
  28. navier_stokes = true,
  29. ns_advection = (sim.ns_advection == 1),
  30. ns_liquid_phase = (sim.solve_Navier_Stokes_liquid_phase == 1),
  31. verbose = true,
  32. show_every = sim.show_every,
  33. electrolysis_convection = (sim.electrolysis_convection == 1),
  34. electrolysis_liquid_phase = true,
  35. electrolysis_phase_change_case = sim.electrolysis_phase_change_case,
  36. imposed_velocity = sim.imposed_velocity,
  37. adapt_timestep_mode = sim.adapt_timestep_mode,
  38. non_dimensionalize = sim.non_dimensionalize,
  39. mode_2d = sim.mode_2d,
  40. breakup = sim.breakup,
  41. # On injecte ici les BC dynamiques présentes
  42. kwargs_bc...
  43. )
  44. end
  45. # Lecture des arguments et du fichier YAML
  46. localARGS = ARGS
  47. if length(localARGS) > 0
  48. yamlfile = localARGS[1]
  49. printstyled(color=:magenta, @sprintf "\n YAML file ")
  50. print(yamlfile)
  51. print("\n")
  52. yamlpath = yamlfile
  53. yamlnamelist = split(yamlfile, "/")
  54. yamlname = yamlnamelist[end]
  55. end
  56. data = YAML.load_file(yamlpath)
  57. # Dictionnaires de configuration
  58. prop_dict = PropertyDict(data)
  59. study = PropertyDict(prop_dict.study)
  60. # Paramètres de convergence
  61. nb_grid_points = study.meshes
  62. n_cases = length(nb_grid_points)
  63. print("\n number of points ", nb_grid_points, "\n")
  64. timesteps = study.timesteps
  65. io = PropertyDict(prop_dict.plot)
  66. flower = PropertyDict(prop_dict.flower)
  67. mesh = PropertyDict(flower.mesh)
  68. sim = PropertyDict(flower.simulation)
  69. phys = PropertyDict(flower.physics)
  70. macros = PropertyDict(flower.macros)
  71. # Initialisation des variables globales via macro
  72. eval(Meta.parseall(macros.print_parameters))
  73. # ----------------------------------------------------------------
  74. # Initialisation PDI (IO)
  75. # ----------------------------------------------------------------
  76. if io.pdi > 0
  77. @debug "Before PDI init"
  78. yml_file = yamlfile
  79. conf = @ccall "libparaconf".PC_parse_path(yml_file::Cstring)::PC_tree_t
  80. getsubyml = @ccall "libparaconf".PC_get(conf::PC_tree_t, ".pdi"::Cstring)::PC_tree_t
  81. local pdi_status = @ccall "libpdi".PDI_init(getsubyml::PC_tree_t)::Cint
  82. # Metadonnées MPI
  83. mpi_coords_x = 1; mpi_coords_y = 1
  84. mpi_max_coords_x = 1; mpi_max_coords_y = 1
  85. local nx = 32
  86. local ny = 32
  87. nstep = 0
  88. phys_time = 0.0
  89. local PDI_status = @ccall "libpdi".PDI_multi_expose("init_PDI"::Cstring,
  90. "mpi_coords_x"::Cstring, mpi_coords_x::Ref{Clonglong}, PDI_OUT::Cint,
  91. "mpi_coords_y"::Cstring, mpi_coords_x::Ref{Clonglong}, PDI_OUT::Cint,
  92. "mpi_max_coords_x"::Cstring, mpi_max_coords_x::Ref{Clonglong}, PDI_OUT::Cint,
  93. "mpi_max_coords_y"::Cstring, mpi_max_coords_y::Ref{Clonglong}, PDI_OUT::Cint,
  94. "nx"::Cstring, nx::Ref{Clonglong}, PDI_OUT::Cint,
  95. "ny"::Cstring, ny::Ref{Clonglong}, PDI_OUT::Cint,
  96. "nb_transported_scalars"::Cstring, phys.nb_transported_scalars::Ref{Clonglong}, PDI_OUT::Cint,
  97. "nb_levelsets"::Cstring, phys.nb_levelsets::Ref{Clonglong}, PDI_OUT::Cint,
  98. "nstep"::Cstring, nstep::Ref{Clonglong}, PDI_OUT::Cint,
  99. C_NULL::Ptr{Cvoid})::Cint
  100. print("\n PDI INIT status ", PDI_status)
  101. end
  102. # Tableaux pour stocker les erreurs
  103. error_list_l1 = zeros(n_cases)
  104. error_list_l2 = zeros(n_cases)
  105. error_list_linfty = zeros(n_cases)
  106. error_list_l1_mixed = zeros(n_cases)
  107. error_list_l2_mixed = zeros(n_cases)
  108. error_list_linfty_mixed = zeros(n_cases)
  109. error_list_l1_full = zeros(n_cases)
  110. error_list_l2_full = zeros(n_cases)
  111. error_list_linfty_full = zeros(n_cases)
  112. cell_volume_list = zeros(n_cases)
  113. base_directory = pwd()
  114. # ----------------------------------------------------------------
  115. # Boucle de Convergence : Timestep
  116. # ----------------------------------------------------------------
  117. for timestep in timesteps
  118. print("\n Timestep ", timestep)
  119. timestep_to_string = @sprintf "timestep_%.4e" timestep
  120. timestep_to_string = replace(timestep_to_string, "." => "_")
  121. mkpath(timestep_to_string)
  122. cd(timestep_to_string)
  123. # ------------------------------------------------------------
  124. # Boucle de Convergence : Mesh
  125. # ------------------------------------------------------------
  126. for (i, study_nb_grid_points) in enumerate(nb_grid_points)
  127. mesh_to_string = @sprintf "mesh_%.5i" study_nb_grid_points
  128. mesh_ratio = Int((mesh.ymax - mesh.ymin)/ (mesh.xmax - mesh.xmin))
  129. print("\n mesh ratio ", mesh_ratio)
  130. study_nb_grid_points_x = study_nb_grid_points
  131. study_nb_grid_points_y = study_nb_grid_points * mesh_ratio
  132. print("\n nx ", study_nb_grid_points_x, " ny ", study_nb_grid_points_y)
  133. mkpath(mesh_to_string)
  134. cd(mesh_to_string)
  135. # Init regular grid
  136. scalar_mesh_x = collect(LinRange(mesh.xmin, mesh.xmax, study_nb_grid_points_x + 1))
  137. scalar_mesh_y = collect(LinRange(mesh.ymin, mesh.ymax, study_nb_grid_points_y + 1))
  138. @debug "Before Numerical"
  139. # Aliases from yml to Flower.jl
  140. aliases = Dict(
  141. :x => :scalar_mesh_x,
  142. :y => :scalar_mesh_y,
  143. :xcoord => :intfc_x,
  144. :ycoord => :intfc_y,
  145. :R => :radius,
  146. :max_iterations => :max_iter,
  147. :save_every => :max_iter,
  148. :ϵ => :epsilon,
  149. :ϵwall => :epsilon_wall,
  150. :nLS => :nb_levelsets,
  151. :θd => :temperature0,
  152. :β => :beta,
  153. :σ => :sigma,
  154. :δreinit => :delta_reinit,
  155. :n_ext_cl => :n_ext,
  156. :timestep_0 => :timestep,
  157. :timestep_n => :timestep,
  158. :io_pdi => :pdi,
  159. )
  160. extra = Dict(
  161. :scalar_mesh_x => scalar_mesh_x,
  162. :scalar_mesh_y => scalar_mesh_y,
  163. )
  164. default = Numerical{Float64,Int}(
  165. x = scalar_mesh_x,
  166. y = scalar_mesh_y,
  167. timestep_n = timestep,
  168. timestep_0 = timestep,
  169. electrolysis_reaction_symb = Symbol(phys.electrolysis_reaction),
  170. bulk_velocity_symb = Symbol(phys.bulk_velocity),
  171. )
  172. print("\n ns_advection ", (sim.ns_advection == 1))
  173. global num_new = safefill_with_aliases_and_extra_already_init(Numerical{Float64,Int}, default,
  174. sim, phys, io, aliases, extra)
  175. global num = num_new
  176. if num.verbosity > 0
  177. print("\n Parameters num ", num)
  178. end
  179. Broadcast.broadcastable(num::Numerical) = Ref(num)
  180. global gp, gu, gv = init_meshes(num)
  181. global op, phS, phL = init_fields(num, gp, gu, gv)
  182. gp.LS[1].u .= 1.0 # deactivate interface
  183. # ------------------------------------------------------------
  184. # EVALUATION DYNAMIQUE (Macros & BC)
  185. # ------------------------------------------------------------
  186. # 1. On exécute TOUTES les macros pour créer les variables dans Main
  187. eval(Meta.parseall(macros.init_fields))
  188. eval(Meta.parseall(macros.boundaries))
  189. eval(Meta.parseall(macros.interface)) # <--- DÉPLACÉ ICI (IMPORTANT)
  190. # 2. Capture des BC dans un dictionnaire pour éviter le "World Age Problem"
  191. bc_dict = Dict{Symbol, Any}()
  192. bc_symbols = [:BC_uL, :BC_uS, :BC_vL, :BC_vS, :BC_pL, :BC_pS, :BC_u, :BC_int, :BC_trans_scal, :BC_phi_ele]
  193. for sym in bc_symbols
  194. if isdefined(Main, sym)
  195. bc_dict[sym] = getfield(Main, sym)
  196. else
  197. # Si la variable n'est pas définie, on ne l'ajoute pas au dict.
  198. # Cela laissera run_forward! utiliser sa valeur par défaut (si elle existe)
  199. # ou plantera avec une erreur plus claire si elle est obligatoire.
  200. end
  201. end
  202. # ------------------------------------------------------------
  203. if num.io_pdi > 0
  204. # Send meta-data to PDI
  205. nx = gp.nx
  206. ny = gp.ny
  207. try
  208. local PDI_status = @ccall "libpdi".PDI_multi_expose("init_PDI"::Cstring,
  209. "mpi_coords_x"::Cstring, mpi_coords_x::Ref{Clonglong}, PDI_OUT::Cint,
  210. "mpi_coords_y"::Cstring, mpi_coords_x::Ref{Clonglong}, PDI_OUT::Cint,
  211. "mpi_max_coords_x"::Cstring, mpi_max_coords_x::Ref{Clonglong}, PDI_OUT::Cint,
  212. "mpi_max_coords_y"::Cstring, mpi_max_coords_y::Ref{Clonglong}, PDI_OUT::Cint,
  213. "nx"::Cstring, nx::Ref{Clonglong}, PDI_OUT::Cint,
  214. "ny"::Cstring, ny::Ref{Clonglong}, PDI_OUT::Cint,
  215. "nb_transported_scalars"::Cstring, phys.nb_transported_scalars::Ref{Clonglong}, PDI_OUT::Cint,
  216. "nb_levelsets"::Cstring, phys.nb_levelsets::Ref{Clonglong}, PDI_OUT::Cint,
  217. "nstep"::Cstring, num.current_iter::Ref{Clonglong}, PDI_OUT::Cint,
  218. "nb_Navier_slip_BC"::Cstring, num.nNavier::Ref{Clonglong}, PDI_OUT::Cint,
  219. "timestep"::Cstring, timestep::Ref{Cdouble}, PDI_OUT::Cint,
  220. C_NULL::Ptr{Cvoid})::Cint
  221. catch error
  222. print("\n Bug init_PDI \n")
  223. print("\n error", error)
  224. end
  225. end
  226. eval(Meta.parseall(macros.interface))
  227. if sim.time_scheme == "FE"
  228. time_scheme = FE
  229. else
  230. time_scheme = CN
  231. end
  232. # --- Sorties PDI Initiale ---
  233. if num.io_pdi > 0
  234. try
  235. iLSpdi = 1
  236. LStable = zeros(gp)
  237. if phys.nb_levelsets > 1
  238. LStable = gp.LS[2].u
  239. end
  240. us = zeros(gp)
  241. vs = zeros(gp)
  242. interpolate_grid_liquid!(gp, gu, gv, phL.u, phL.v, us, vs)
  243. current_radius = phys.radius
  244. PDI_status = @ccall "libpdi".PDI_multi_expose("write_initialization"::Cstring,
  245. "nstep"::Cstring, num.current_iter::Ref{Clonglong}, PDI_OUT::Cint,
  246. "time"::Cstring, phys_time::Ref{Cdouble}, PDI_OUT::Cint,
  247. "u_1D"::Cstring, phL.uD::Ptr{Cdouble}, PDI_OUT::Cint,
  248. "v_1D"::Cstring, phL.vD::Ptr{Cdouble}, PDI_OUT::Cint,
  249. "p_1D"::Cstring, phL.pD::Ptr{Cdouble}, PDI_OUT::Cint,
  250. "levelset_p"::Cstring, gp.LS[iLSpdi].u::Ptr{Cdouble}, PDI_OUT::Cint,
  251. "levelset_u"::Cstring, gu.LS[iLSpdi].u::Ptr{Cdouble}, PDI_OUT::Cint,
  252. "levelset_v"::Cstring, gv.LS[iLSpdi].u::Ptr{Cdouble}, PDI_OUT::Cint,
  253. "levelset_p_wall"::Cstring, LStable::Ptr{Cdouble}, PDI_OUT::Cint,
  254. "phi_ele_1D"::Cstring, phL.phi_eleD::Ptr{Cdouble}, PDI_OUT::Cint,
  255. "velocity_x"::Cstring, us::Ptr{Cdouble}, PDI_OUT::Cint,
  256. "velocity_y"::Cstring, vs::Ptr{Cdouble}, PDI_OUT::Cint,
  257. "radius"::Cstring, current_radius::Ref{Cdouble}, PDI_OUT::Cint,
  258. C_NULL::Ptr{Cvoid})::Cint
  259. catch error
  260. printstyled(color=:red, @sprintf "\n PDI error \n")
  261. print(error)
  262. end
  263. end
  264. # --- Sorties PDI Post-process bubble ---
  265. velocity_y_bubble = 0.0 .* gp.LS[end].geoS.dcap[:,:,5]
  266. volume_fraction = gp.LS[end].geoS.dcap[:,:,5]
  267. iLSpdi = 1
  268. velocity_y = velocity_y_bubble
  269. PDI_status = @ccall "libpdi".PDI_multi_expose("post_processing_rising_bubble"::Cstring,
  270. "nstep"::Cstring, num.current_iter ::Ref{Clonglong}, PDI_OUT::Cint,
  271. "velocity_y"::Cstring, velocity_y::Ptr{Cdouble}, PDI_OUT::Cint,
  272. "volume_fraction"::Cstring, volume_fraction::Ptr{Cdouble}, PDI_OUT::Cint,
  273. "volume_liq_cell"::Cstring, gp.LS[iLSpdi].geoL.dcap[:,:,5]::Ptr{Cdouble}, PDI_OUT::Cint,
  274. "volume_cell"::Cstring, gp.LS[iLSpdi].geoS.dcap[:,:,5]::Ptr{Cdouble}, PDI_OUT::Cint,
  275. "mesh_p_x"::Cstring, gp.x::Ptr{Cdouble}, PDI_OUT::Cint,
  276. "mesh_p_y"::Cstring, gp.y::Ptr{Cdouble}, PDI_OUT::Cint,
  277. "dcap_1"::Cstring, gp.LS[iLSpdi].geoS.dcap[:,:,1]::Ptr{Cdouble}, PDI_OUT::Cint,
  278. "dcap_2"::Cstring, gp.LS[iLSpdi].geoS.dcap[:,:,2]::Ptr{Cdouble}, PDI_OUT::Cint,
  279. "dcap_3"::Cstring, gp.LS[iLSpdi].geoS.dcap[:,:,3]::Ptr{Cdouble}, PDI_OUT::Cint,
  280. "dcap_4"::Cstring, gp.LS[iLSpdi].geoS.dcap[:,:,4]::Ptr{Cdouble}, PDI_OUT::Cint,
  281. C_NULL::Ptr{Cvoid})::Cint
  282. # -----------------------------------------------------------------------------------------
  283. # APPEL DU SOLVEUR via FUNCTION BARRIER + INVOKELATEST
  284. # C'est ici que la correction opère : on passe le dictionnaire 'bc_dict' via invokelatest
  285. # -----------------------------------------------------------------------------------------
  286. @debug "Before run_forward wrapper"
  287. Base.invokelatest(
  288. execute_simulation_step,
  289. num, gp, gu, gv, op, phS, phL, sim, phys, time_scheme, bc_dict
  290. )
  291. @debug "After run"
  292. # -----------------------------------------------------------------------------------------
  293. # Calcul d'erreurs (si demandé)
  294. if study.compute_errors != "None"
  295. LIQUID = gp.ind.all_indices[gp.LS[1].geoL.cap[:,:,5] .> (1-1e-16)]
  296. MIXED = gp.ind.all_indices[gp.LS[1].geoL.cap[:,:,5] .<= (1-1e-16) .&& gp.LS[1].geoL.cap[:,:,5] .> 1e-16]
  297. if study.compute_errors == "Poiseuille"
  298. l1, l2, linfty = relative_errors(phL.v, vPoiseuille, vcat(LIQUID, MIXED), gp.LS[1].geoL.cap[:,:,5], num.Δ)
  299. l1_mixed, l2_mixed, linfty_mixed = relative_errors(phL.v, vPoiseuille, MIXED, gp.LS[1].geoL.cap[:,:,5], num.Δ)
  300. l1_full, l2_full, linfty_full = relative_errors(phL.v, vPoiseuille, LIQUID, gp.LS[1].geoL.cap[:,:,5], num.Δ)
  301. elseif study.compute_errors == "diffusion_full_cell"
  302. L = mesh.xmax - mesh.xmin
  303. D = num.diffusion_coeff[2]
  304. analytical_nx = 1000
  305. diffusion_time_scale = L^2 / D
  306. ele_current_i = -1.59e4
  307. F1 = ele_current_i / (2 * num.Faraday * D)
  308. analytical_dx = L / analytical_nx
  309. c0 = num.concentration0[2]
  310. max_nb_Fourier_series = 1000
  311. function full_cell_u1(x, t)
  312. return F1 * x
  313. end
  314. function full_cell_A_n(n, L, F1, dx, c0)
  315. if n == 0
  316. return -F1*L + 2*c0
  317. else
  318. return (-2*F1*L)/(n*π)^2*((-1)^n-1)
  319. end
  320. end
  321. function full_cell_u2(x, t, L, D, max_nb_Fourier_series, c0, analytical_dx)
  322. result = sum(full_cell_A_n(n, L, F1, analytical_dx, c0) * cos(n * π * x / L) * exp(-D * (n * π / L)^2 * t) for n in 1:max_nb_Fourier_series)
  323. result += full_cell_A_n(0, L, F1, analytical_dx, c0) * cos(0 * π * x / L) * exp(-D * (0 * π / L)^2 * t) / 2
  324. return result
  325. end
  326. function full_cell_u(x, t, L, D, max_nb_Fourier_series, c0, analytical_dx)
  327. return full_cell_u1(x, t) + full_cell_u2(x, t, L, D, max_nb_Fourier_series, c0, analytical_dx)
  328. end
  329. concentration_profile = full_cell_u.(gp.x[2,:], num.time, L, num.diffusion_coeff[2], max_nb_Fourier_series, c0, analytical_dx)
  330. l1, l2, linfty = relative_errors(phL.trans_scal[:,:,2], concentration_profile, vcat(LIQUID, MIXED), gp.LS[1].geoL.cap[:,:,5], num.Δ)
  331. l1_mixed, l2_mixed, linfty_mixed = relative_errors(phL.trans_scal[:,:,2], concentration_profile, MIXED, gp.LS[1].geoL.cap[:,:,5], num.Δ)
  332. l1_full, l2_full, linfty_full = relative_errors(phL.trans_scal[:,:,2], concentration_profile, LIQUID, gp.LS[1].geoL.cap[:,:,5], num.Δ)
  333. end
  334. error_list_l1[i] = l1
  335. error_list_l2[i] = l2
  336. error_list_linfty[i] = linfty
  337. error_list_l1_mixed[i] = l1_mixed
  338. error_list_l2_mixed[i] = l2_mixed
  339. error_list_linfty_mixed[i] = linfty_mixed
  340. error_list_l1_full[i] = l1_full
  341. error_list_l2_full[i] = l2_full
  342. error_list_linfty_full[i] = linfty_full
  343. cell_volume_list[i] = minimum(gp.LS[1].geoL.dcap[:,:,5])
  344. min_cell_volume = minimum(gp.LS[1].geoL.dcap[:,:,5])
  345. local PDI_status = @ccall "libpdi".PDI_multi_expose("convergence_study_iter"::Cstring,
  346. "study_nb_grid_points"::Cstring, study_nb_grid_points::Ref{Clong}, PDI_OUT::Cint,
  347. "study_timestep"::Cstring, timestep::Ref{Cdouble}, PDI_OUT::Cint,
  348. "study_l1_rel_error"::Cstring, l1::Ref{Cdouble}, PDI_OUT::Cint,
  349. "study_l2_rel_error"::Cstring, l2::Ref{Cdouble}, PDI_OUT::Cint,
  350. "study_linfty_rel_error"::Cstring, linfty::Ref{Cdouble}, PDI_OUT::Cint,
  351. "study_l1_rel_error_full_cells"::Cstring, l1_full::Ref{Cdouble}, PDI_OUT::Cint,
  352. "study_l2_rel_error_full_cells"::Cstring, l2_full::Ref{Cdouble}, PDI_OUT::Cint,
  353. "study_linfty_rel_error_full_cells"::Cstring, linfty_full::Ref{Cdouble}, PDI_OUT::Cint,
  354. "study_l1_rel_error_partial_cells"::Cstring, l1_mixed::Ref{Cdouble}, PDI_OUT::Cint,
  355. "study_l2_rel_error_partial_cells"::Cstring, l2_mixed::Ref{Cdouble}, PDI_OUT::Cint,
  356. "study_linfty_rel_error_partial_cells"::Cstring, linfty_mixed::Ref{Cdouble}, PDI_OUT::Cint,
  357. "domain_length"::Cstring, L0::Ref{Cdouble}, PDI_OUT::Cint,
  358. "min_cell_volume"::Cstring, min_cell_volume::Ref{Cdouble}, PDI_OUT::Cint,
  359. C_NULL::Ptr{Cvoid})::Cint
  360. end
  361. current_directory = pwd()
  362. if current_directory == base_directory*"/"*timestep_to_string*"/"*mesh_to_string
  363. cd("..")
  364. else
  365. print("\n Error in mesh subdirectory", current_directory, " not ", base_directory*"/"*timestep_to_string*"/"*mesh_to_string)
  366. exit()
  367. end
  368. end # end mesh convergence
  369. current_directory = pwd()
  370. if current_directory == base_directory*"/"*timestep_to_string
  371. cd("..")
  372. else
  373. print("\n Error in timestep subdirectory", current_directory, " not ", base_directory*"/"*timestep_to_string)
  374. exit()
  375. end
  376. end # end timestep convergence
  377. # Finalisation PDI et Tests
  378. min_cell_volume = minimum(gp.LS[1].geoL.cap[:,:,5])
  379. print("\n min_cell_volume ", min_cell_volume, " type ", typeof(min_cell_volume))
  380. if study.compute_errors != "None"
  381. local PDI_status = @ccall "libpdi".PDI_multi_expose("convergence_study"::Cstring,
  382. "n_tests"::Cstring, n_cases::Ref{Clonglong}, PDI_OUT::Cint,
  383. "nx_list"::Cstring, nb_grid_points::Ptr{Clonglong}, PDI_OUT::Cint,
  384. "cell_volume_list"::Cstring, cell_volume_list::Ptr{Cdouble}, PDI_OUT::Cint,
  385. "l1_rel_error"::Cstring, error_list_l1::Ptr{Cdouble}, PDI_OUT::Cint,
  386. "l2_rel_error"::Cstring, error_list_l2::Ptr{Cdouble}, PDI_OUT::Cint,
  387. "linfty_rel_error"::Cstring, error_list_linfty::Ptr{Cdouble}, PDI_OUT::Cint,
  388. "l1_rel_error_full_cells"::Cstring, error_list_l1_full::Ptr{Cdouble}, PDI_OUT::Cint,
  389. "l2_rel_error_full_cells"::Cstring, error_list_l2_full::Ptr{Cdouble}, PDI_OUT::Cint,
  390. "linfty_rel_error_full_cells"::Cstring, error_list_linfty_full::Ptr{Cdouble}, PDI_OUT::Cint,
  391. "l1_rel_error_partial_cells"::Cstring, error_list_l1_mixed::Ptr{Cdouble}, PDI_OUT::Cint,
  392. "l2_rel_error_partial_cells"::Cstring, error_list_l2_mixed::Ptr{Cdouble}, PDI_OUT::Cint,
  393. "linfty_rel_error_partial_cells"::Cstring, error_list_linfty_mixed::Ptr{Cdouble}, PDI_OUT::Cint,
  394. "domain_length"::Cstring, L0::Ref{Cdouble}, PDI_OUT::Cint,
  395. "min_cell_volume"::Cstring, min_cell_volume::Ref{Cdouble}, PDI_OUT::Cint,
  396. C_NULL::Ptr{Cvoid})::Cint
  397. end
  398. if io.pdi > 0
  399. try
  400. local PDI_status = @ccall "libpdi".PDI_finalize()::Cint
  401. catch error
  402. printstyled(color=:red, @sprintf "\n PDI error \n")
  403. print(error)
  404. end
  405. end
  406. printstyled(color=:red, @sprintf "\n After PDI \n")
  407. if haskey(macros, "test_end")
  408. eval(Meta.parseall(macros.test_end))
  409. end