void VisualizeMesh(socketstream &sock, const char *vishost, int visport, ParMesh &pmesh, const char *title, int x, int y, int w, int h, const char *keys, bool vec) { MPI_Comm comm = pmesh.GetComm(); int num_procs, myid; MPI_Comm_size(comm, &num_procs); MPI_Comm_rank(comm, &myid); bool newly_opened = false; int connection_failed; do { if (myid == 0) { if (!sock.is_open() || !sock) { sock.open(vishost, visport); sock.precision(8); newly_opened = true; } sock << "solution\n"; } pmesh.PrintAsOne(sock); if (myid == 0 && newly_opened) { sock << "window_title '" << title << "'\n" << "window_geometry " << x << " " << y << " " << w << " " << h << "\n"; if ( keys ) { sock << "keys " << keys << "\n"; } else { sock << "keys maaAc"; } if ( vec ) { sock << "vvv"; } sock << endl; } if (myid == 0) { connection_failed = !sock && !newly_opened; } MPI_Bcast(&connection_failed, 1, MPI_INT, 0, comm); } while (connection_failed); }
int main(int argc, char *argv[]) { // 1. Initialize MPI. int num_procs, myid; MPI_Init(&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD, &num_procs); MPI_Comm_rank(MPI_COMM_WORLD, &myid); // 2. Parse command-line options. const char *mesh_file = "../data/beam-quad.mesh"; int ser_ref_levels = 2; int par_ref_levels = 0; int order = 2; int ode_solver_type = 3; double t_final = 300.0; double dt = 3; double visc = 1e-2; bool visualization = true; int vis_steps = 1; OptionsParser args(argc, argv); args.AddOption(&mesh_file, "-m", "--mesh", "Mesh file to use."); args.AddOption(&ser_ref_levels, "-rs", "--refine-serial", "Number of times to refine the mesh uniformly in serial."); args.AddOption(&par_ref_levels, "-rp", "--refine-parallel", "Number of times to refine the mesh uniformly in parallel."); args.AddOption(&order, "-o", "--order", "Order (degree) of the finite elements."); args.AddOption(&ode_solver_type, "-s", "--ode-solver", "ODE solver: 1 - Backward Euler, 2 - SDIRK2, 3 - SDIRK3,\n\t" "\t 11 - Forward Euler, 12 - RK2, 13 - RK3 SSP, 14 - RK4."); args.AddOption(&t_final, "-tf", "--t-final", "Final time; start time is 0."); args.AddOption(&dt, "-dt", "--time-step", "Time step."); args.AddOption(&visc, "-v", "--viscosity", "Viscosity coefficient."); args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", "--no-visualization", "Enable or disable GLVis visualization."); args.AddOption(&vis_steps, "-vs", "--visualization-steps", "Visualize every n-th timestep."); args.Parse(); if (!args.Good()) { if (myid == 0) args.PrintUsage(cout); MPI_Finalize(); return 1; } if (myid == 0) args.PrintOptions(cout); // 3. Read the serial mesh from the given mesh file on all processors. We can // handle triangular, quadrilateral, tetrahedral and hexahedral meshes // with the same code. Mesh *mesh; ifstream imesh(mesh_file); if (!imesh) { if (myid == 0) cerr << "\nCan not open mesh file: " << mesh_file << '\n' << endl; MPI_Finalize(); return 2; } mesh = new Mesh(imesh, 1, 1); imesh.close(); int dim = mesh->Dimension(); // 4. Define the ODE solver used for time integration. Several implicit // singly diagonal implicit Runge-Kutta (SDIRK) methods, as well as // explicit Runge-Kutta methods are available. ODESolver *ode_solver; switch (ode_solver_type) { // Implicit L-stable methods case 1: ode_solver = new BackwardEulerSolver; break; case 2: ode_solver = new SDIRK23Solver(2); break; case 3: ode_solver = new SDIRK33Solver; break; // Explicit methods case 11: ode_solver = new ForwardEulerSolver; break; case 12: ode_solver = new RK2Solver(0.5); break; // midpoint method case 13: ode_solver = new RK3SSPSolver; break; case 14: ode_solver = new RK4Solver; break; // Implicit A-stable methods (not L-stable) case 22: ode_solver = new ImplicitMidpointSolver; break; case 23: ode_solver = new SDIRK23Solver; break; case 24: ode_solver = new SDIRK34Solver; break; default: if (myid == 0) cout << "Unknown ODE solver type: " << ode_solver_type << '\n'; MPI_Finalize(); return 3; } // 5. Refine the mesh in serial to increase the resolution. In this example // we do 'ser_ref_levels' of uniform refinement, where 'ser_ref_levels' is // a command-line parameter. for (int lev = 0; lev < ser_ref_levels; lev++) mesh->UniformRefinement(); // 6. Define a parallel mesh by a partitioning of the serial mesh. Refine // this mesh further in parallel to increase the resolution. Once the // parallel mesh is defined, the serial mesh can be deleted. ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh); delete mesh; for (int lev = 0; lev < par_ref_levels; lev++) pmesh->UniformRefinement(); // 7. Define the parallel vector finite element spaces representing the mesh // deformation x_gf, the velocity v_gf, and the initial configuration, // x_ref. Define also the elastic energy density, w_gf, which is in a // discontinuous higher-order space. Since x and v are integrated in time // as a system, we group them together in block vector vx, on the unique // parallel degrees of freedom, with offsets given by array true_offset. H1_FECollection fe_coll(order, dim); ParFiniteElementSpace fespace(pmesh, &fe_coll, dim); int glob_size = fespace.GlobalTrueVSize(); if (myid == 0) cout << "Number of velocity/deformation unknowns: " << glob_size << endl; int true_size = fespace.TrueVSize(); Array<int> true_offset(3); true_offset[0] = 0; true_offset[1] = true_size; true_offset[2] = 2*true_size; BlockVector vx(true_offset); ParGridFunction v_gf(&fespace), x_gf(&fespace); ParGridFunction x_ref(&fespace); pmesh->GetNodes(x_ref); L2_FECollection w_fec(order + 1, dim); ParFiniteElementSpace w_fespace(pmesh, &w_fec); ParGridFunction w_gf(&w_fespace); // 8. Set the initial conditions for v_gf, x_gf and vx, and define the // boundary conditions on a beam-like mesh (see description above). VectorFunctionCoefficient velo(dim, InitialVelocity); v_gf.ProjectCoefficient(velo); VectorFunctionCoefficient deform(dim, InitialDeformation); x_gf.ProjectCoefficient(deform); v_gf.GetTrueDofs(vx.GetBlock(0)); x_gf.GetTrueDofs(vx.GetBlock(1)); Array<int> ess_bdr(fespace.GetMesh()->bdr_attributes.Max()); ess_bdr = 0; ess_bdr[0] = 1; // boundary attribute 1 (index 0) is fixed // 9. Initialize the hyperelastic operator, the GLVis visualization and print // the initial energies. HyperelasticOperator oper(fespace, ess_bdr, visc); socketstream vis_v, vis_w; if (visualization) { char vishost[] = "localhost"; int visport = 19916; vis_v.open(vishost, visport); vis_v.precision(8); visualize(vis_v, pmesh, &x_gf, &v_gf, "Velocity", true); // Make sure all ranks have sent their 'v' solution before initiating // another set of GLVis connections (one from each rank): MPI_Barrier(pmesh->GetComm()); vis_w.open(vishost, visport); if (vis_w) { oper.GetElasticEnergyDensity(x_gf, w_gf); vis_w.precision(8); visualize(vis_w, pmesh, &x_gf, &w_gf, "Elastic energy density", true); } } double ee0 = oper.ElasticEnergy(x_gf); double ke0 = oper.KineticEnergy(v_gf); if (myid == 0) { cout << "initial elastic energy (EE) = " << ee0 << endl; cout << "initial kinetic energy (KE) = " << ke0 << endl; cout << "initial total energy (TE) = " << (ee0 + ke0) << endl; } // 10. Perform time-integration (looping over the time iterations, ti, with a // time-step dt). ode_solver->Init(oper); double t = 0.0; bool last_step = false; for (int ti = 1; !last_step; ti++) { if (t + dt >= t_final - dt/2) last_step = true; ode_solver->Step(vx, t, dt); if (last_step || (ti % vis_steps) == 0) { v_gf.Distribute(vx.GetBlock(0)); x_gf.Distribute(vx.GetBlock(1)); double ee = oper.ElasticEnergy(x_gf); double ke = oper.KineticEnergy(v_gf); if (myid == 0) cout << "step " << ti << ", t = " << t << ", EE = " << ee << ", KE = " << ke << ", ΔTE = " << (ee+ke)-(ee0+ke0) << endl; if (visualization) { visualize(vis_v, pmesh, &x_gf, &v_gf); if (vis_w) { oper.GetElasticEnergyDensity(x_gf, w_gf); visualize(vis_w, pmesh, &x_gf, &w_gf); } } } } // 11. Save the displaced mesh, the velocity and elastic energy. { GridFunction *nodes = &x_gf; int owns_nodes = 0; pmesh->SwapNodes(nodes, owns_nodes); ostringstream mesh_name, velo_name, ee_name; mesh_name << "deformed." << setfill('0') << setw(6) << myid; velo_name << "velocity." << setfill('0') << setw(6) << myid; ee_name << "elastic_energy." << setfill('0') << setw(6) << myid; ofstream mesh_ofs(mesh_name.str().c_str()); mesh_ofs.precision(8); pmesh->Print(mesh_ofs); pmesh->SwapNodes(nodes, owns_nodes); ofstream velo_ofs(velo_name.str().c_str()); velo_ofs.precision(8); v_gf.Save(velo_ofs); ofstream ee_ofs(ee_name.str().c_str()); ee_ofs.precision(8); oper.GetElasticEnergyDensity(x_gf, w_gf); w_gf.Save(ee_ofs); } // 10. Free the used memory. delete ode_solver; delete pmesh; MPI_Finalize(); return 0; }
int main(int argc, char *argv[]) { // 1. Initialize MPI. MPI_Session mpi(argc, argv); int myid = mpi.WorldRank(); // print the cool banner if (mpi.Root()) { display_banner(cout); } // 2. Parse command-line options. const char *mesh_file = "cylinder-hex.mesh"; int ser_ref_levels = 0; int par_ref_levels = 0; int order = 2; int ode_solver_type = 1; double t_final = 100.0; double dt = 0.5; double amp = 2.0; double mu = 1.0; double sigma = 2.0*M_PI*10; double Tcapacity = 1.0; double Tconductivity = 0.01; double alpha = Tconductivity/Tcapacity; double freq = 1.0/60.0; bool visualization = true; bool visit = true; int vis_steps = 1; int gfprint = 0; const char *basename = "Joule"; int amr = 0; int debug = 0; const char *problem = "rod"; OptionsParser args(argc, argv); args.AddOption(&mesh_file, "-m", "--mesh", "Mesh file to use."); args.AddOption(&ser_ref_levels, "-rs", "--refine-serial", "Number of times to refine the mesh uniformly in serial."); args.AddOption(&par_ref_levels, "-rp", "--refine-parallel", "Number of times to refine the mesh uniformly in parallel."); args.AddOption(&order, "-o", "--order", "Order (degree) of the finite elements."); args.AddOption(&ode_solver_type, "-s", "--ode-solver", "ODE solver: 1 - Backward Euler, 2 - SDIRK2, 3 - SDIRK3\n\t." "\t 22 - Mid-Point, 23 - SDIRK23, 34 - SDIRK34."); args.AddOption(&t_final, "-tf", "--t-final", "Final time; start time is 0."); args.AddOption(&dt, "-dt", "--time-step", "Time step."); args.AddOption(&mu, "-mu", "--permeability", "Magnetic permeability coefficient."); args.AddOption(&sigma, "-cnd", "--sigma", "Conductivity coefficient."); args.AddOption(&freq, "-f", "--frequency", "Frequency of oscillation."); args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", "--no-visualization", "Enable or disable GLVis visualization."); args.AddOption(&visit, "-visit", "--visit", "-no-visit", "--no-visit", "Enable or disable VisIt visualization."); args.AddOption(&vis_steps, "-vs", "--visualization-steps", "Visualize every n-th timestep."); args.AddOption(&basename, "-k", "--outputfilename", "Name of the visit dump files"); args.AddOption(&gfprint, "-print", "--print", "Print results (grid functions) to disk."); args.AddOption(&amr, "-amr", "--amr", "Enable AMR"); args.AddOption(&STATIC_COND, "-sc", "--static-condensation", "Enable static condensation"); args.AddOption(&debug, "-debug", "--debug", "Print matrices and vectors to disk"); args.AddOption(&SOLVER_PRINT_LEVEL, "-hl", "--hypre-print-level", "Hypre print level"); args.AddOption(&problem, "-p", "--problem", "Name of problem to run"); args.Parse(); if (!args.Good()) { if (mpi.Root()) { args.PrintUsage(cout); } return 1; } if (mpi.Root()) { args.PrintOptions(cout); } aj_ = amp; mj_ = mu; sj_ = sigma; wj_ = 2.0*M_PI*freq; kj_ = sqrt(0.5*wj_*mj_*sj_); hj_ = alpha; dtj_ = dt; rj_ = 1.0; if (mpi.Root()) { cout << "\nSkin depth sqrt(2.0/(wj*mj*sj)) = " << sqrt(2.0/(wj_*mj_*sj_)) << "\nSkin depth sqrt(2.0*dt/(mj*sj)) = " << sqrt(2.0*dt/(mj_*sj_)) << endl; } // 3. Here material properties are assigned to mesh attributes. This code is // not general, it is assumed the mesh has 3 regions each with a different // integer attribute: 1, 2 or 3. // // The coil problem has three regions: 1) coil, 2) air, 3) the rod. // The rod problem has two regions: 1) rod, 2) air. // // We can use the same material maps for both problems. std::map<int, double> sigmaMap, InvTcondMap, TcapMap, InvTcapMap; double sigmaAir; double TcondAir; double TcapAir; if (strcmp(problem,"rod")==0 || strcmp(problem,"coil")==0) { sigmaAir = 1.0e-6 * sigma; TcondAir = 1.0e6 * Tconductivity; TcapAir = 1.0 * Tcapacity; } else { cerr << "Problem " << problem << " not recognized\n"; mfem_error(); } if (strcmp(problem,"rod")==0 || strcmp(problem,"coil")==0) { sigmaMap.insert(pair<int, double>(1, sigma)); sigmaMap.insert(pair<int, double>(2, sigmaAir)); sigmaMap.insert(pair<int, double>(3, sigmaAir)); InvTcondMap.insert(pair<int, double>(1, 1.0/Tconductivity)); InvTcondMap.insert(pair<int, double>(2, 1.0/TcondAir)); InvTcondMap.insert(pair<int, double>(3, 1.0/TcondAir)); TcapMap.insert(pair<int, double>(1, Tcapacity)); TcapMap.insert(pair<int, double>(2, TcapAir)); TcapMap.insert(pair<int, double>(3, TcapAir)); InvTcapMap.insert(pair<int, double>(1, 1.0/Tcapacity)); InvTcapMap.insert(pair<int, double>(2, 1.0/TcapAir)); InvTcapMap.insert(pair<int, double>(3, 1.0/TcapAir)); } else { cerr << "Problem " << problem << " not recognized\n"; mfem_error(); } // 4. Read the serial mesh from the given mesh file on all processors. We can // handle triangular, quadrilateral, tetrahedral and hexahedral meshes // with the same code. Mesh *mesh; mesh = new Mesh(mesh_file, 1, 1); int dim = mesh->Dimension(); // 5. Assign the boundary conditions Array<int> ess_bdr(mesh->bdr_attributes.Max()); Array<int> thermal_ess_bdr(mesh->bdr_attributes.Max()); Array<int> poisson_ess_bdr(mesh->bdr_attributes.Max()); if (strcmp(problem,"coil")==0) { // BEGIN CODE FOR THE COIL PROBLEM // For the coil in a box problem we have surfaces 1) coil end (+), // 2) coil end (-), 3) five sides of box, 4) side of box with coil BC ess_bdr = 0; ess_bdr[0] = 1; // boundary attribute 4 (index 3) is fixed ess_bdr[1] = 1; // boundary attribute 4 (index 3) is fixed ess_bdr[2] = 1; // boundary attribute 4 (index 3) is fixed ess_bdr[3] = 1; // boundary attribute 4 (index 3) is fixed // Same as above, but this is for the thermal operator for HDiv // formulation the essential BC is the flux thermal_ess_bdr = 0; thermal_ess_bdr[2] = 1; // boundary attribute 4 (index 3) is fixed // Same as above, but this is for the poisson eq for H1 formulation the // essential BC is the value of Phi poisson_ess_bdr = 0; poisson_ess_bdr[0] = 1; // boundary attribute 1 (index 0) is fixed poisson_ess_bdr[1] = 1; // boundary attribute 2 (index 1) is fixed // END CODE FOR THE COIL PROBLEM } else if (strcmp(problem,"rod")==0) { // BEGIN CODE FOR THE STRAIGHT ROD PROBLEM // the boundary conditions below are for the straight rod problem ess_bdr = 0; ess_bdr[0] = 1; // boundary attribute 1 (index 0) is fixed (front) ess_bdr[1] = 1; // boundary attribute 2 (index 1) is fixed (rear) ess_bdr[2] = 1; // boundary attribute 3 (index 2) is fixed (outer) // Same as above, but this is for the thermal operator. For HDiv // formulation the essential BC is the flux, which is zero on the front // and sides. Note the Natural BC is T = 0 on the outer surface. thermal_ess_bdr = 0; thermal_ess_bdr[0] = 1; // boundary attribute 1 (index 0) is fixed (front) thermal_ess_bdr[1] = 1; // boundary attribute 2 (index 1) is fixed (rear) // Same as above, but this is for the poisson eq for H1 formulation the // essential BC is the value of Phi poisson_ess_bdr = 0; poisson_ess_bdr[0] = 1; // boundary attribute 1 (index 0) is fixed (front) poisson_ess_bdr[1] = 1; // boundary attribute 2 (index 1) is fixed (back) // END CODE FOR THE STRAIGHT ROD PROBLEM } else { cerr << "Problem " << problem << " not recognized\n"; mfem_error(); } // The following is required for mesh refinement mesh->EnsureNCMesh(); // 6. Define the ODE solver used for time integration. Several implicit // methods are available, including singly diagonal implicit Runge-Kutta // (SDIRK). ODESolver *ode_solver; switch (ode_solver_type) { // Implicit L-stable methods case 1: ode_solver = new BackwardEulerSolver; break; case 2: ode_solver = new SDIRK23Solver(2); break; case 3: ode_solver = new SDIRK33Solver; break; // Implicit A-stable methods (not L-stable) case 22: ode_solver = new ImplicitMidpointSolver; break; case 23: ode_solver = new SDIRK23Solver; break; case 34: ode_solver = new SDIRK34Solver; break; default: if (mpi.Root()) { cout << "Unknown ODE solver type: " << ode_solver_type << '\n'; } delete mesh; return 3; } // 7. Refine the mesh in serial to increase the resolution. In this example // we do 'ser_ref_levels' of uniform refinement, where 'ser_ref_levels' is // a command-line parameter. for (int lev = 0; lev < ser_ref_levels; lev++) { mesh->UniformRefinement(); } // 8. Define a parallel mesh by a partitioning of the serial mesh. Refine // this mesh further in parallel to increase the resolution. Once the // parallel mesh is defined, the serial mesh can be deleted. ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh); delete mesh; for (int lev = 0; lev < par_ref_levels; lev++) { pmesh->UniformRefinement(); } // Make sure tet-only meshes are marked for local refinement. pmesh->Finalize(true); // 9. Apply non-uniform non-conforming mesh refinement to the mesh. The // whole metal region is refined once, before the start of the time loop, // i.e. this is not based on any error estimator. if (amr == 1) { Array<int> ref_list; int numElems = pmesh->GetNE(); for (int ielem = 0; ielem < numElems; ielem++) { int thisAtt = pmesh->GetAttribute(ielem); if (thisAtt == 1) { ref_list.Append(ielem); } } pmesh->GeneralRefinement(ref_list); ref_list.DeleteAll(); } // 10. Reorient the mesh. Must be done after refinement but before definition // of higher order Nedelec spaces pmesh->ReorientTetMesh(); // 11. Rebalance the mesh. Since the mesh was adaptively refined in a // non-uniform way it will be computationally unbalanced. if (pmesh->Nonconforming()) { pmesh->Rebalance(); } // 12. Define the parallel finite element spaces. We use: // // H(curl) for electric field, // H(div) for magnetic flux, // H(div) for thermal flux, // H(grad)/H1 for electrostatic potential, // L2 for temperature // L2 contains discontinuous "cell-center" finite elements, type 2 is // "positive" L2_FECollection L2FEC(order-1, dim); // ND contains Nedelec "edge-centered" vector finite elements with continuous // tangential component. ND_FECollection HCurlFEC(order, dim); // RT contains Raviart-Thomas "face-centered" vector finite elements with // continuous normal component. RT_FECollection HDivFEC(order-1, dim); // H1 contains continuous "node-centered" Lagrange finite elements. H1_FECollection HGradFEC(order, dim); ParFiniteElementSpace L2FESpace(pmesh, &L2FEC); ParFiniteElementSpace HCurlFESpace(pmesh, &HCurlFEC); ParFiniteElementSpace HDivFESpace(pmesh, &HDivFEC); ParFiniteElementSpace HGradFESpace(pmesh, &HGradFEC); // The terminology is TrueVSize is the unique (non-redundant) number of dofs HYPRE_Int glob_size_l2 = L2FESpace.GlobalTrueVSize(); HYPRE_Int glob_size_nd = HCurlFESpace.GlobalTrueVSize(); HYPRE_Int glob_size_rt = HDivFESpace.GlobalTrueVSize(); HYPRE_Int glob_size_h1 = HGradFESpace.GlobalTrueVSize(); if (mpi.Root()) { cout << "Number of Temperature Flux unknowns: " << glob_size_rt << endl; cout << "Number of Temperature unknowns: " << glob_size_l2 << endl; cout << "Number of Electric Field unknowns: " << glob_size_nd << endl; cout << "Number of Magnetic Field unknowns: " << glob_size_rt << endl; cout << "Number of Electrostatic unknowns: " << glob_size_h1 << endl; } int Vsize_l2 = L2FESpace.GetVSize(); int Vsize_nd = HCurlFESpace.GetVSize(); int Vsize_rt = HDivFESpace.GetVSize(); int Vsize_h1 = HGradFESpace.GetVSize(); // the big BlockVector stores the fields as // 0 Temperature // 1 Temperature Flux // 2 P field // 3 E field // 4 B field // 5 Joule Heating Array<int> true_offset(7); true_offset[0] = 0; true_offset[1] = true_offset[0] + Vsize_l2; true_offset[2] = true_offset[1] + Vsize_rt; true_offset[3] = true_offset[2] + Vsize_h1; true_offset[4] = true_offset[3] + Vsize_nd; true_offset[5] = true_offset[4] + Vsize_rt; true_offset[6] = true_offset[5] + Vsize_l2; // The BlockVector is a large contiguous chunk of memory for storing required // data for the hypre vectors, in this case: the temperature L2, the T-flux // HDiv, the E-field HCurl, and the B-field HDiv, and scalar potential P. BlockVector F(true_offset); // grid functions E, B, T, F, P, and w which is the Joule heating ParGridFunction E_gf, B_gf, T_gf, F_gf, w_gf, P_gf; T_gf.MakeRef(&L2FESpace,F, true_offset[0]); F_gf.MakeRef(&HDivFESpace,F, true_offset[1]); P_gf.MakeRef(&HGradFESpace,F,true_offset[2]); E_gf.MakeRef(&HCurlFESpace,F,true_offset[3]); B_gf.MakeRef(&HDivFESpace,F, true_offset[4]); w_gf.MakeRef(&L2FESpace,F, true_offset[5]); // 13. Get the boundary conditions, set up the exact solution grid functions // These VectorCoefficients have an Eval function. Note that e_exact and // b_exact in this case are exact analytical solutions, taking a 3-vector // point as input and returning a 3-vector field VectorFunctionCoefficient E_exact(3, e_exact); VectorFunctionCoefficient B_exact(3, b_exact); FunctionCoefficient T_exact(t_exact); E_exact.SetTime(0.0); B_exact.SetTime(0.0); // 14. Initialize the Diffusion operator, the GLVis visualization and print // the initial energies. MagneticDiffusionEOperator oper(true_offset[6], L2FESpace, HCurlFESpace, HDivFESpace, HGradFESpace, ess_bdr, thermal_ess_bdr, poisson_ess_bdr, mu, sigmaMap, TcapMap, InvTcapMap, InvTcondMap); // This function initializes all the fields to zero or some provided IC oper.Init(F); socketstream vis_T, vis_E, vis_B, vis_w, vis_P; char vishost[] = "localhost"; int visport = 19916; if (visualization) { // Make sure all ranks have sent their 'v' solution before initiating // another set of GLVis connections (one from each rank): MPI_Barrier(pmesh->GetComm()); vis_T.precision(8); vis_E.precision(8); vis_B.precision(8); vis_P.precision(8); vis_w.precision(8); int Wx = 0, Wy = 0; // window position int Ww = 350, Wh = 350; // window size int offx = Ww+10, offy = Wh+45; // window offsets miniapps::VisualizeField(vis_P, vishost, visport, P_gf, "Electric Potential (Phi)", Wx, Wy, Ww, Wh); Wx += offx; miniapps::VisualizeField(vis_E, vishost, visport, E_gf, "Electric Field (E)", Wx, Wy, Ww, Wh); Wx += offx; miniapps::VisualizeField(vis_B, vishost, visport, B_gf, "Magnetic Field (B)", Wx, Wy, Ww, Wh); Wx = 0; Wy += offy; miniapps::VisualizeField(vis_w, vishost, visport, w_gf, "Joule Heating", Wx, Wy, Ww, Wh); Wx += offx; miniapps::VisualizeField(vis_T, vishost, visport, T_gf, "Temperature", Wx, Wy, Ww, Wh); } // VisIt visualization VisItDataCollection visit_dc(basename, pmesh); if ( visit ) { visit_dc.RegisterField("E", &E_gf); visit_dc.RegisterField("B", &B_gf); visit_dc.RegisterField("T", &T_gf); visit_dc.RegisterField("w", &w_gf); visit_dc.RegisterField("Phi", &P_gf); visit_dc.RegisterField("F", &F_gf); visit_dc.SetCycle(0); visit_dc.SetTime(0.0); visit_dc.Save(); } E_exact.SetTime(0.0); B_exact.SetTime(0.0); // 15. Perform time-integration (looping over the time iterations, ti, with a // time-step dt). The object oper is the MagneticDiffusionOperator which // has a Mult() method and an ImplicitSolve() method which are used by // the time integrators. ode_solver->Init(oper); double t = 0.0; bool last_step = false; for (int ti = 1; !last_step; ti++) { if (t + dt >= t_final - dt/2) { last_step = true; } // F is the vector of dofs, t is the current time, and dt is the time step // to advance. ode_solver->Step(F, t, dt); if (debug == 1) { oper.Debug(basename,t); } if (gfprint == 1) { ostringstream T_name, E_name, B_name, F_name, w_name, P_name, mesh_name; T_name << basename << "_" << setfill('0') << setw(6) << t << "_" << "T." << setfill('0') << setw(6) << myid; E_name << basename << "_" << setfill('0') << setw(6) << t << "_" << "E." << setfill('0') << setw(6) << myid; B_name << basename << "_" << setfill('0') << setw(6) << t << "_" << "B." << setfill('0') << setw(6) << myid; F_name << basename << "_" << setfill('0') << setw(6) << t << "_" << "F." << setfill('0') << setw(6) << myid; w_name << basename << "_" << setfill('0') << setw(6) << t << "_" << "w." << setfill('0') << setw(6) << myid; P_name << basename << "_" << setfill('0') << setw(6) << t << "_" << "P." << setfill('0') << setw(6) << myid; mesh_name << basename << "_" << setfill('0') << setw(6) << t << "_" << "mesh." << setfill('0') << setw(6) << myid; ofstream mesh_ofs(mesh_name.str().c_str()); mesh_ofs.precision(8); pmesh->Print(mesh_ofs); mesh_ofs.close(); ofstream T_ofs(T_name.str().c_str()); T_ofs.precision(8); T_gf.Save(T_ofs); T_ofs.close(); ofstream E_ofs(E_name.str().c_str()); E_ofs.precision(8); E_gf.Save(E_ofs); E_ofs.close(); ofstream B_ofs(B_name.str().c_str()); B_ofs.precision(8); B_gf.Save(B_ofs); B_ofs.close(); ofstream F_ofs(F_name.str().c_str()); F_ofs.precision(8); F_gf.Save(B_ofs); F_ofs.close(); ofstream P_ofs(P_name.str().c_str()); P_ofs.precision(8); P_gf.Save(P_ofs); P_ofs.close(); ofstream w_ofs(w_name.str().c_str()); w_ofs.precision(8); w_gf.Save(w_ofs); w_ofs.close(); } if (last_step || (ti % vis_steps) == 0) { double el = oper.ElectricLosses(E_gf); if (mpi.Root()) { cout << fixed; cout << "step " << setw(6) << ti << ",\tt = " << setw(6) << setprecision(3) << t << ",\tdot(E, J) = " << setprecision(8) << el << endl; } // Make sure all ranks have sent their 'v' solution before initiating // another set of GLVis connections (one from each rank): MPI_Barrier(pmesh->GetComm()); if (visualization) { int Wx = 0, Wy = 0; // window position int Ww = 350, Wh = 350; // window size int offx = Ww+10, offy = Wh+45; // window offsets miniapps::VisualizeField(vis_P, vishost, visport, P_gf, "Electric Potential (Phi)", Wx, Wy, Ww, Wh); Wx += offx; miniapps::VisualizeField(vis_E, vishost, visport, E_gf, "Electric Field (E)", Wx, Wy, Ww, Wh); Wx += offx; miniapps::VisualizeField(vis_B, vishost, visport, B_gf, "Magnetic Field (B)", Wx, Wy, Ww, Wh); Wx = 0; Wy += offy; miniapps::VisualizeField(vis_w, vishost, visport, w_gf, "Joule Heating", Wx, Wy, Ww, Wh); Wx += offx; miniapps::VisualizeField(vis_T, vishost, visport, T_gf, "Temperature", Wx, Wy, Ww, Wh); } if (visit) { visit_dc.SetCycle(ti); visit_dc.SetTime(t); visit_dc.Save(); } } } if (visualization) { vis_T.close(); vis_E.close(); vis_B.close(); vis_w.close(); vis_P.close(); } // 16. Free the used memory. delete ode_solver; delete pmesh; return 0; }