Compare commits

...
Author SHA1 Message Date
Robert W. Anderson 90b9bcb894 vis script 2021-09-03 09:22:28 -07:00
Robert W. Anderson 018650dffa add lookahead refine method 2021-09-03 07:28:47 -07:00
Robert W. Anderson c138d2920a pulse plus bump problem 2021-09-02 20:31:48 -07:00
Robert W. Anderson f07d934d79 add problem 3 - two interacting pulses 2021-09-02 15:15:05 -07:00
Robert W. Anderson 450a9cf439 fix up output 2021-09-02 15:12:32 -07:00
Robert W. Anderson 1d0f63f32d add switch for output of per-cycle solns 2021-09-02 12:19:24 -07:00
Robert W. Anderson 5b99b7bf2a make save-reference executable 2021-09-01 22:06:45 -07:00
Robert W. Anderson 6b848930d3 improve brute force search script 2021-09-01 22:06:08 -07:00
Robert W. Anderson bf2c0124c3 fix up output of cycle errors 2021-09-01 22:05:40 -07:00
Robert W. Anderson 6a5646d496 fix filename 2021-09-01 21:29:28 -07:00
Robert W. Anderson af3c94676e script util to generate unit periodic mesh of any size 2021-09-01 21:28:50 -07:00
Robert W. Anderson c97e168859 add script which combines the glvis figures and error plots into a combined view 2021-09-01 20:58:49 -07:00
Robert W. Anderson 62d0606810 script for generating the list of screenshot cmds for glvis. The output of this gets inserted into make-glvis-figs 2021-09-01 20:56:56 -07:00
Robert W. Anderson 556bc2a7e9 insert script for making per-timestep glvis figures 2021-09-01 20:55:22 -07:00
Robert W. Anderson 1778e84837 matplotlib script for per-cycle error plots 2021-09-01 20:50:58 -07:00
Robert W. Anderson 94ff6a9dbb script to save reference solution 2021-09-01 20:48:37 -07:00
Robert W. Anderson eec8e0fe13 brute force search script 2021-09-01 20:48:18 -07:00
Robert W. Anderson b9468ef974 output errors on reference mesh 2021-09-01 20:33:22 -07:00
Robert W. Anderson 6594bb1460 more gitignore items 2021-09-01 20:27:31 -07:00
Robert W. Anderson ebcc2b5467 this isn't a mergeable branch anyway - change gitignore 2021-09-01 20:25:15 -07:00
Robert W. Anderson 331271ba7b add periodic 1d mesh files 2021-09-01 08:30:41 -07:00
Robert W. Anderson a43dd69fd2 fixes for the greedy method 2021-08-31 21:07:49 -07:00
Robert W. Anderson c7cb61b8db begin greedy method with reference soln error 2021-08-31 19:55:15 -07:00
Robert W. Anderson cadb80652f use multi-element refinement strategy, build and use reference numbering maps to manage this 2021-08-29 22:48:04 -07:00
Robert W. Anderson 84e4bd4210 add amr update routines, modify 1d problem 2021-08-28 22:58:42 -07:00
Robert W. Anderson f9ca033e08 add amr_update routine, add adaption to beginning of loop, add comparison with reference soln 2021-08-28 22:57:55 -07:00
Robert W. Anderson 66fd2b8892 add the point matrices for interpolation of segments in 1D 2021-08-28 22:56:43 -07:00
Robert W. Anderson a7b527416f make segment a tensor product type element 2021-08-28 22:56:05 -07:00
Robert W. Anderson 42cf5ae9e3 add 1d support for ex18 and a start at amr 2021-08-28 15:11:37 -07:00
15 changed files with 1157 additions and 97 deletions
+7
View File
@@ -52,6 +52,13 @@ examples/ex1[0-9]p
examples/ex2[0-9]
examples/ex2[0-9]p
examples/soln-*
examples/reference-*
examples/*.dat
examples/*.gif
examples/*.mp4
examples/*.gf
examples/refined.mesh
examples/displaced.mesh
examples/mesh.*
+30
View File
@@ -0,0 +1,30 @@
#!/bin/bash
# Use imagemagick to combine the figures into a composite view
for i in {0..19}; do
ii=`printf %04d $i`
# label reference density
convert reference-$ii.png -gravity south -annotate -50+50 "Reference Fine" ,reference-$ii.png
# label optimal density
convert opt-soln-$ii.png -gravity south -annotate -50+50 "Optimal AMR" ,opt-soln-$ii.png
# label greedy density
convert greedy-soln-$ii.png -gravity south -annotate -50+50 "Max Current AMR" ,greedy-soln-$ii.png
# stack optimal on top of error plot
convert ,opt-soln-$ii.png opt-err-$i.png -append ,opt-soln-werr-$ii.png
# stack greedy on top of error plot
convert ,greedy-soln-$ii.png greedy-err-$i.png -append ,greedy-soln-werr-$ii.png
# lay the 3 side by side
convert ,reference-$ii.png ,opt-soln-werr-$ii.png ,greedy-soln-werr-$ii.png +append ,ref-sbs-soln-$ii.1.png
# Label the composite image with timestep
convert ,ref-sbs-soln-$ii.1.png -gravity northwest -annotate +20+20 "Timestep $i" ref-sbs-soln-$ii.png
done
rm ,*
+576 -40
View File
@@ -42,6 +42,7 @@
#include <fstream>
#include <sstream>
#include <iostream>
#include <set>
// Classes FE_Evolution, RiemannSolver, DomainIntegrator and FaceIntegrator
// shared between the serial and parallel version of the example.
@@ -50,14 +51,177 @@
// Choice for the problem setup. See InitialCondition in ex18.hpp.
int problem;
// The dim and hence number of equations is taken from the mesh.
int dim;
int num_equation;
// Equation constant parameters.
const int num_equation = 4;
const double specific_heat_ratio = 1.4;
const double gas_constant = 1.0;
// Maximum characteristic speed (updated by integrators)
double max_char_speed;
void amr_update(FiniteElementSpace& fes,
FiniteElementSpace& dfes,
FiniteElementSpace& vfes,
BlockVector& u_block,
GridFunction& rho,
GridFunction& rho_u,
GridFunction& rho_e,
GridFunction& sol)
{
fes.Update();
dfes.Update();
vfes.Update();
rho.Update();
rho_u.Update();
rho_e.Update();
Array<int> offsets(num_equation + 1);
for (int k = 0; k <= num_equation; k++) {
offsets[k] = k * vfes.GetNDofs();
}
u_block.Update(offsets);
Vector& sub0 = u_block.GetBlock(0);
Vector& sub1 = u_block.GetBlock(1);
Vector& sub2 = u_block.GetBlock(2);
sub0 = rho;
sub1 = rho_u;
sub2 = rho_e;
sol.MakeRef(&vfes, u_block.GetData());
rho.MakeRef(&fes, u_block.GetData() + offsets[0]);
rho_u.MakeRef(&dfes, u_block.GetData() + offsets[1]);
rho_e.MakeRef(&fes, u_block.GetData() + offsets[2]);
}
double estimate_dt(double cfl, Mesh& mesh,
GridFunction& sol, NonlinearForm& A, int order)
{
// Determine the minimum element size.
double hmin = 0.0;
hmin = mesh.GetElementSize(0, 1);
for (int i = 1; i < mesh.GetNE(); i++)
{
hmin = min(mesh.GetElementSize(i, 1), hmin);
}
double dt = -0.01;
// Find a safe dt, using a temporary vector. Calling Mult() computes the
// maximum char speed at all quadrature points on all faces.
Vector z(A.Width());
max_char_speed = 0.;
A.Mult(sol, z);
dt = cfl * hmin / max_char_speed / (2*order+1);
return dt;
}
void show_maps(Mesh& mesh, vector<int>& coarse_map, vector<int>& fine_map)
{
for (int i = 0; i < mesh.GetNE(); i++) {
int depth = mesh.ncmesh->GetElementDepth(i);
if (depth == 0) {
printf("| %2d ",i);
}
else {
printf("|%2d|%2d",i,i+1);
i++;
}
}
printf("| mesh i\n");
for (size_t i = 0; i < coarse_map.size(); i++) {
printf("| %2d ",coarse_map[i]);
}
printf("| coarse map\n");
for (size_t i = 0; i < coarse_map.size(); i++) {
printf("| %2d ",fine_map[i]);
}
printf("| fine map\n");
for (size_t i = 0; i < coarse_map.size(); i++) {
printf("| %2lu ",i);
}
printf("| ref idx\n");
// some validation checks
for (size_t i = 0; i < coarse_map.size(); i++) {
//printf("checking reference index %d\n",i);
if (coarse_map[i] > -1) assert( fine_map[i] == -1);
if (fine_map[i] > -1) assert(coarse_map[i] == -1);
if (coarse_map[i] > -1) assert(mesh.ncmesh->GetElementDepth(coarse_map[i]) == 0);
if (fine_map[i] > -1) assert(mesh.ncmesh->GetElementDepth(fine_map[i]) == 1);
if (fine_map[i] > -1) assert(mesh.ncmesh->GetElementDepth(fine_map[i]+1) == 1);
}
}
void compute_reference_errors(int ti,
FiniteElementCollection& fec,
Mesh& mesh,
GridFunction& den,
const vector<int>& coarse_map,
const vector<int>& fine_map,
vector<double>& errors)
{
// Create a temp copy of the mesh for refinement to reference resolution
Mesh tmp_mesh(mesh);
FiniteElementSpace tmp_fes(&tmp_mesh, &fec);
GridFunction tmp_den(&tmp_fes);
tmp_den = den; // copy data
// refine mesh and soln to reference resolution
Array<int> refs;
for (int i = 0; i < tmp_mesh.GetNE(); i++) {
if (tmp_mesh.ncmesh->GetElementDepth(i) == 0) {
refs.Append(i);
}
}
tmp_mesh.GeneralRefinement(refs);
tmp_den.FESpace()->Update();
tmp_den.Update();
// read in reference mesh
ostringstream fn;
fn << "reference-" << ti << ".mesh";
Mesh ref_mesh(fn.str().c_str());
// read in reference density
ostringstream sol_name;
sol_name << "reference-" << ti << "-" << 0 << ".gf";
ifstream gf_ifs(sol_name.str());
GridFunction ref_den(&ref_mesh, gf_ifs);
// integrate L2 errors
GridFunctionCoefficient ref_den_coeff(&ref_den);
Vector err(ref_mesh.GetNE());
tmp_den.ComputeElementL2Errors(ref_den_coeff, err);
{
ostringstream sol_name;
sol_name << "refined-current-rho-" << ti << ".gf";
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs << tmp_den;
}
// sum L2 errors to reference mesh. The reference errors are always
// on a fully refined mesh.
int k = 0;
for (size_t i = 0; i < coarse_map.size(); i++) {
double e0 = err[k];
double e1 = err[k+1];
errors[i] = sqrt(e0*e0+e1*e1);
k += 2;
}
}
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
@@ -69,8 +233,15 @@ int main(int argc, char *argv[])
double t_final = 2.0;
double dt = -0.01;
double cfl = 0.3;
bool visualization = true;
bool visualization = false;
int vis_steps = 50;
Array<int> rseq;
int nseq = 0;
int regrid_period = 1;
int greedy_refine = 0;
int lookahead_refine = 0;
int output_cycle_soln = 0;
int output_cycle_errors = 0;
int precision = 8;
cout.precision(precision);
@@ -98,6 +269,18 @@ int main(int argc, char *argv[])
"Enable or disable GLVis visualization.");
args.AddOption(&vis_steps, "-vs", "--visualization-steps",
"Visualize every n-th timestep.");
args.AddOption(&rseq, "-rseq", "--refine-sequence",
"Element sequence to refine.");
args.AddOption(&regrid_period, "-rp", "--regrid-period",
"Timesteps per regrid.");
args.AddOption(&greedy_refine, "-gr", "--greedy-refine",
"Use greedy refinement strategy.");
args.AddOption(&lookahead_refine, "-lr", "--lookahead-refine",
"Use lookahead refinement strategy.");
args.AddOption(&output_cycle_soln, "-cs", "--output-cycle-solutions",
"Output per-cycle solutions.");
args.AddOption(&output_cycle_errors, "-ce", "--output-cycle-errors",
"Output per-cycle errors.");
args.Parse();
if (!args.Good())
@@ -107,12 +290,15 @@ int main(int argc, char *argv[])
}
args.PrintOptions(cout);
printf("dt = %f\n",dt);
// 2. Read the mesh from the given mesh file. This example requires a 2D
// periodic mesh, such as ../data/periodic-square.mesh.
Mesh mesh(mesh_file, 1, 1);
mesh.EnsureNCMesh();
const int dim = mesh.Dimension();
MFEM_ASSERT(dim == 2, "Need a two-dimensional mesh for the problem definition");
num_equation = 2+dim;
// 3. Define the ODE solver used for time integration. Several explicit
// Runge-Kutta methods are available.
@@ -162,7 +348,9 @@ int main(int argc, char *argv[])
BlockVector u_block(offsets);
// Momentum grid function on dfes for visualization.
GridFunction mom(&dfes, u_block.GetData() + offsets[1]);
GridFunction rho(&fes, u_block.GetData() + offsets[0]);
GridFunction rho_u(&dfes, u_block.GetData() + offsets[1]);
GridFunction rho_e(&fes, u_block.GetData() + offsets[2]);
// Initialize the state.
VectorFunctionCoefficient u0(num_equation, InitialCondition);
@@ -184,6 +372,7 @@ int main(int argc, char *argv[])
sol_ofs.precision(precision);
sol_ofs << uk;
}
}
// 7. Set up the nonlinear form corresponding to the DG discretization of the
@@ -199,7 +388,7 @@ int main(int argc, char *argv[])
// 8. Define the time-dependent evolution operator describing the ODE
// right-hand side, and perform time-integration (looping over the time
// iterations, ti, with a time-step dt).
FE_Evolution euler(vfes, A, Aflux.SpMat());
FE_Evolution euler(vfes, A, Aflux);
// Visualize the density
socketstream sout;
@@ -219,7 +408,7 @@ int main(int argc, char *argv[])
else
{
sout.precision(precision);
sout << "solution\n" << mesh << mom;
sout << "solution\n" << mesh << rho;
sout << "pause\n";
sout << flush;
cout << "GLVis visualization paused."
@@ -227,17 +416,6 @@ int main(int argc, char *argv[])
}
}
// Determine the minimum element size.
double hmin = 0.0;
if (cfl > 0)
{
hmin = mesh.GetElementSize(0, 1);
for (int i = 1; i < mesh.GetNE(); i++)
{
hmin = min(mesh.GetElementSize(i, 1), hmin);
}
}
// Start the timer.
tic_toc.Clear();
tic_toc.Start();
@@ -246,27 +424,348 @@ int main(int argc, char *argv[])
euler.SetTime(t);
ode_solver->Init(euler);
if (cfl > 0)
{
// Find a safe dt, using a temporary vector. Calling Mult() computes the
// maximum char speed at all quadrature points on all faces.
Vector z(A.Width());
max_char_speed = 0.;
A.Mult(sol, z);
dt = cfl * hmin / max_char_speed / (2*order+1);
// map from base coarse numbering to current coarse numbering.
// -1 entries for elements that are currently refined.
vector<int> coarse_map(mesh.GetNE());
for (size_t i = 0; i < coarse_map.size(); ++i) {
coarse_map[i] = i;
}
// map from base coarse numbering to current fine numbering. The
// second element is always this index+1.
// -1 entries for elements that are currently coarse.
vector<int> fine_map(mesh.GetNE());
for (size_t i = 0; i < fine_map.size(); ++i) {
fine_map[i] = -1;
}
//show_maps(mesh,coarse_map,fine_map);
// vector<int> coarse_map(mesh.GetNE());
// for (int i = 0; i < coarse_map.size(); ++i) {
// coarse_map[i] = i;
// }
// the elements that are currently refined
set<int> cur_ref_set; // in base numbering
// Integrate in time.
bool done = false;
for (int ti = 0; !done; )
{
if (greedy_refine && !(ti % regrid_period )) {
vector<double> ref_errors(coarse_map.size());
compute_reference_errors(ti, fec, mesh, rho,
coarse_map, fine_map, ref_errors);
vector<double>::iterator it;
it = std::max_element(ref_errors.begin(), ref_errors.end());
int ref_max = std::distance(ref_errors.begin(), it);
std::cout << "max at: " << std::distance(ref_errors.begin(), it) << '\n';
rseq.SetSize(nseq+1);
rseq[nseq] = ref_max;
}
if (lookahead_refine && !(ti % regrid_period )) {
MFEM_ASSERT(cfl < 0, "need fixed time step for lookahead.");
double dt_real = min(dt, t_final - t);
// advance a copy of the solution
GridFunction tmp_sol(sol);
ode_solver->Step(tmp_sol, t, dt_real);
GridFunction tmp_rho(&fes, tmp_sol);
vector<double> ref_errors(coarse_map.size());
compute_reference_errors(ti+1, fec, mesh, tmp_rho,
coarse_map, fine_map, ref_errors);
vector<double>::iterator it;
it = std::max_element(ref_errors.begin(), ref_errors.end());
int ref_max = std::distance(ref_errors.begin(), it);
std::cout << "max at: " << std::distance(ref_errors.begin(), it) << '\n';
rseq.SetSize(nseq+1);
rseq[nseq] = ref_max;
}
// adapt mesh to new element(s)
if (rseq.Size() && !(ti % regrid_period )) {
//printf("*** begin refinement ***\n");
set<int> new_ref_set; // in base numbering
// use base numbering
int ne = coarse_map.size();
int el1 = rseq[nseq++];
int el2 = el1-1;
int el3 = el1+1;
el2 = (el2 + ne) % ne;
el3 = (el3 + ne) % ne;
new_ref_set.insert(el1);
new_ref_set.insert(el2);
new_ref_set.insert(el3);
// The coarsen set is elements from cur_ref_set not in new_ref_set
set<int> coarsen_set;
std::set_difference(cur_ref_set.begin(), cur_ref_set.end(),
new_ref_set.begin(), new_ref_set.end(),
std::inserter(coarsen_set, coarsen_set.begin()));
// The refine set is elements from new_ref_set not in cur_ref_set
set<int> refine_set;
std::set_difference(new_ref_set.begin(), new_ref_set.end(),
cur_ref_set.begin(), cur_ref_set.end(),
std::inserter(refine_set, refine_set.begin()));
set<int>::iterator it;
// printf("cur_ref set\n");
//
// for (it = cur_ref_set.begin(); it != cur_ref_set.end(); ++it) {
// const int& i = *it;
// printf("%d ",i);
// }
// printf("\n");
// printf("new_ref set\n");
// for (it = new_ref_set.begin(); it != new_ref_set.end(); ++it) {
// const int& i = *it;
// printf("%d ",i);
// }
// printf("\n");
// printf("refine set: ");
// for (it = refine_set.begin(); it != refine_set.end(); ++it) {
// const int& i = *it;
// printf("%d ",i);
// }
// printf("\n");
// printf("coarsen set: ");
// for (it = coarsen_set.begin(); it != coarsen_set.end(); ++it) {
// const int& i = *it;
// printf("%d ",i);
// }
// printf("\n");
// Perform any new refinements. Translate into current numbering.
Array<int> els;
for (it = refine_set.begin(); it != refine_set.end(); ++it) {
const int& i = *it;
assert(coarse_map[i] >= 0);
//printf("adding %d -> %d to be refined\n",i,coarse_map[i]);
els.Append(coarse_map[i]);
}
if (els.Size()) {
//printf(" ** start refinements **\n");
mesh.GeneralRefinement(els);
const CoarseFineTransformations &cft = mesh.GetRefinementTransforms();
//printf("updating coarse_map and fine_map after refinement\n");
Table c2f;
cft.GetCoarseToFineMap(mesh, c2f);
Array<int> row;
for (size_t i = 0; i < coarse_map.size(); ++i) {
int old = coarse_map[i];
if (old > -1) {
// was coarse
c2f.GetRow(old,row);
if (row.Size() == 1) {
// was coarse, still coarse
coarse_map[i] = row[0];
}
else {
// was coarse, now fine
coarse_map[i] = -1;
fine_map[i] = row[0];
}
}
else {
// was fine, still fine
old = fine_map[i];
assert(old != -1);
c2f.GetRow(old,row);
assert(row.Size() == 1);
fine_map[i] = row[0];
}
}
// printf("new coarse_map is:\n");
// for (size_t i = 0; i < coarse_map.size(); i++) {
// printf("%lu -> %d\n",i,coarse_map[i]);
// }
// printf("new fine_map is:\n");
// for (size_t i = 0; i < fine_map.size(); i++) {
// printf("%lu -> %d\n",i,fine_map[i]);
// }
amr_update(fes, dfes, vfes, u_block, rho, rho_u, rho_e, sol);
A.Update();
Aflux.Update();
Aflux.Assemble();
euler.Update();
ode_solver->Init(euler);
//printf(" ** done refinements **\n");
//printf("maps after refinement\n");
//show_maps(mesh,coarse_map,fine_map);
}
cur_ref_set = new_ref_set;
// Perform any new derefinements
if (coarsen_set.size()) {
//printf(" ** start derefinements **\n");
Array<double> mock_error(mesh.GetNE());
mock_error = 1.0;
// We only mark one of the fine elements, but that's fine
// because we can set the threshold low enough to always
// derefine.
for (it = coarsen_set.begin(); it != coarsen_set.end(); ++it) {
const int& i = *it;
//printf("coarsening ref idx %d\n",i);
assert(coarse_map[i] == -1);
int i1 = fine_map[i];
//printf("which is fine element %d (and +1)\n",i1);
assert(i1 >= 0);
mock_error[i1] = 0.0;
//printf("setting mock error to 0.0 in %d\n",i1);
}
mesh.DerefineByError(mock_error, 2.0);
amr_update(fes, dfes, vfes, u_block, rho, rho_u, rho_e, sol);
A.Update();
Aflux.Update();
Aflux.Assemble();
euler.Update();
ode_solver->Init(euler);
//printf("updating coarse_map and fine_map after derefinement\n");
const CoarseFineTransformations& cft = mesh.ncmesh->GetDerefinementTransforms();
Table c2f;
cft.GetCoarseToFineMap(mesh, c2f);
//c2f.Print();
Array<int> row;
map<int,int> old2new;
for (int i = 0; i < c2f.Size(); ++i) {
c2f.GetRow(i,row);
for (int j = 0; j < row.Size(); j++) {
old2new[row[j]] = i;
}
}
// map<int,int>::iterator it;
// printf("old2new\n");
// for (it = old2new.begin(); it != old2new.end(); ++it) {
// printf("%d -> %d\n",it->first,it->second);
// }
for (size_t i = 0; i < coarse_map.size(); i++) {
//printf("ref i = %lu\n",i);
int jfine = fine_map[i];
int jcoarse = coarse_map[i];
//printf("mesh j old grid (fine) = %d\n",jfine);
if (jfine > -1) {
int newj = old2new[jfine];
//printf("mesh j new grid (coarse) = %d\n",newj);
c2f.GetRow(newj,row);
if (row.Size() > 1) {
//printf(" was fine, now coarse\n");
// was fine, now coarse
coarse_map[i] = newj;
fine_map[i] = -1;
}
else {
//printf(" was fine, still fine\n");
// was fine, still fine
fine_map[i] = newj;
}
}
//printf("mesh j old grid coarse = %d\n",jcoarse);
if (jcoarse > -1) {
int newj = old2new[jcoarse];
coarse_map[i] = newj;
}
}
// printf("new coarse_map is:\n");
// for (size_t i = 0; i < coarse_map.size(); i++) {
// printf("%lu -> %d\n",i,coarse_map[i]);
// }
// printf("new fine_map is:\n");
// for (size_t i = 0; i < fine_map.size(); i++) {
// printf("%lu -> %d\n",i,fine_map[i]);
// }
//printf(" ** done derefinements **\n");
//printf("maps after derefinement\n");
//show_maps(mesh,coarse_map,fine_map);
}
}
// Output the current solution.
if (output_cycle_soln) {
ostringstream fn;
fn << "soln-" << ti << ".mesh";
ofstream mesh_ofs(fn.str());
mesh_ofs.precision(precision);
mesh_ofs << mesh;
for (int k = 0; k < num_equation; k++)
{
GridFunction uk(&fes, u_block.GetBlock(k));
ostringstream sol_name;
sol_name << "soln-" << ti << "-" << k << ".gf";
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs.precision(precision);
sol_ofs << uk;
}
}
// Output the current error on the reference mesh
if (output_cycle_errors) {
vector<double> ref_errors(coarse_map.size());
compute_reference_errors(ti, fec, mesh, rho,
coarse_map, fine_map, ref_errors);
ostringstream fn;
fn << "err-" << ti << ".dat";
ofstream err_ofs(fn.str());
vector<double>::iterator it;
for (it = ref_errors.begin(); it != ref_errors.end(); ++it) {
int i = std::distance(ref_errors.begin(), it);
double err = *it;
// "mark" refinements with negation. We'll use this to vis
// the refined regions on the error plots.
if (coarse_map[i] < 0) err *= -1;
err_ofs << i << " " << err << endl;
}
}
if (cfl > 0) {
dt = estimate_dt(cfl, mesh, sol, A, order);
}
double dt_real = min(dt, t_final - t);
ode_solver->Step(sol, t, dt_real);
if (cfl > 0)
{
dt = cfl * hmin / max_char_speed / (2*order+1);
}
ti++;
done = (t >= t_final - 1e-8*dt);
@@ -275,9 +774,10 @@ int main(int argc, char *argv[])
cout << "time step: " << ti << ", time: " << t << endl;
if (visualization)
{
sout << "solution\n" << mesh << mom << flush;
sout << "solution\n" << mesh << rho_u << flush;
}
}
}
tic_toc.Stop();
@@ -285,21 +785,57 @@ int main(int argc, char *argv[])
// 9. Save the final solution. This output can be viewed later using GLVis:
// "glvis -m vortex.mesh -g vortex-1-final.gf".
for (int k = 0; k < num_equation; k++)
{
GridFunction uk(&fes, u_block.GetBlock(k));
ostringstream sol_name;
sol_name << "vortex-" << k << "-final.gf";
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs.precision(precision);
sol_ofs << uk;
ofstream mesh_ofs("vortex-final.mesh");
mesh_ofs.precision(precision);
mesh_ofs << mesh;
for (int k = 0; k < num_equation; k++)
{
GridFunction uk(&fes, u_block.GetBlock(k));
ostringstream sol_name;
sol_name << "vortex-" << k << "-final.gf";
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs.precision(precision);
sol_ofs << uk;
}
}
// 10. Compute the L2 solution error summed for all components.
if (t_final == 2.0)
if (rseq.Size())
{
const double error = sol.ComputeLpError(2, u0);
cout << "Solution error: " << error << endl;
// const CoarseFineTransformations& cft = mesh.GetRefinementTransforms();
// Table c2f;
// cft.GetCoarseToFineMap(mesh, c2f);
// Refine to the reference mesh by refining every coarse el that
// wasn't refined.
Array<int> refs;
for (int i = 0; i < mesh.GetNE(); i++) {
if (mesh.ncmesh->GetElementDepth(i) == 0) {
refs.Append(i);
}
}
mesh.GeneralRefinement(refs);
amr_update(fes, dfes, vfes, u_block, rho, rho_u, rho_e, sol);
Mesh mesh_ref("reference.mesh");
ifstream rho_ifs("reference-rho.gf");
ifstream rho_u_ifs("reference-rho-u.gf");
ifstream rho_e_ifs("reference-rho-e.gf");
GridFunction rho_ref(&mesh_ref, rho_ifs);
GridFunction rho_u_ref(&mesh_ref, rho_u_ifs);
GridFunction rho_e_ref(&mesh_ref, rho_e_ifs);
rho_ref.Print();
rho.Print();
GridFunctionCoefficient rho_ref_coeff(&rho_ref);
const double err = rho.ComputeL2Error(rho_ref_coeff);
printf("final L2 error %e\n",err);
// const double error = sol.ComputeLpError(2, u0);
// cout << "Solution error: " << error << endl;
}
// Free the used memory.
+182 -55
View File
@@ -11,7 +11,8 @@ extern int problem;
// Maximum characteristic speed (updated by integrators)
extern double max_char_speed;
extern const int num_equation;
extern int num_equation;
extern const double specific_heat_ratio;
extern const double gas_constant;
@@ -24,7 +25,8 @@ private:
FiniteElementSpace &vfes;
Operator &A;
SparseMatrix &Aflux;
MixedBilinearForm& Aflux;
//SparseMatrix &Aflux;
DenseTensor Me_inv;
mutable Vector state;
@@ -36,10 +38,13 @@ private:
public:
FE_Evolution(FiniteElementSpace &vfes_,
Operator &A_, SparseMatrix &Aflux_);
Operator &A_,
MixedBilinearForm &Aflux_);
virtual void Mult(const Vector &x, Vector &y) const;
void Update();
virtual ~FE_Evolution() { }
};
@@ -100,7 +105,7 @@ public:
// Implementation of class FE_Evolution
FE_Evolution::FE_Evolution(FiniteElementSpace &vfes_,
Operator &A_, SparseMatrix &Aflux_)
Operator &A_, MixedBilinearForm &Aflux_)
: TimeDependentOperator(A_.Height()),
dim(vfes_.GetFE(0)->GetDim()),
vfes(vfes_),
@@ -123,6 +128,32 @@ FE_Evolution::FE_Evolution(FiniteElementSpace &vfes_,
inv.Factor();
inv.GetInverseMatrix(Me_inv(i));
}
//Aflux.Assemble();
}
void FE_Evolution::Update()
{
height = width = A.Height();
Me_inv.SetSize(vfes.GetFE(0)->GetDof(),
vfes.GetFE(0)->GetDof(),
vfes.GetNE());
Aflux.Assemble();
// Standard local assembly and inversion for energy mass matrices.
const int dof = vfes.GetFE(0)->GetDof();
DenseMatrix Me(dof);
DenseMatrixInverse inv(&Me);
MassIntegrator mi;
for (int i = 0; i < vfes.GetNE(); i++)
{
mi.AssembleElementMatrix(*vfes.GetFE(i), *vfes.GetElementTransformation(i), Me);
inv.Factor();
inv.GetInverseMatrix(Me_inv(i));
}
z.SetSize(A.Height());
}
void FE_Evolution::Mult(const Vector &x, Vector &y) const
@@ -385,6 +416,8 @@ void FaceIntegrator::AssembleFaceVector(const FiniteElement &el1,
FaceElementTransformations &Tr,
const Vector &elfun, Vector &elvect)
{
int dim = el1.GetDim();
// Compute the term <F.n(u),[w]> on the interior faces.
const int dof1 = el1.GetDof();
const int dof2 = el2.GetDof();
@@ -424,16 +457,25 @@ void FaceIntegrator::AssembleFaceVector(const FiniteElement &el1,
Tr.SetAllIntPoints(&ip); // set face and element int. points
const IntegrationPoint &eip1 = Tr.GetElement1IntPoint();
const IntegrationPoint &eip2 = Tr.GetElement2IntPoint();
// Calculate basis functions on both elements at the face
el1.CalcShape(Tr.GetElement1IntPoint(), shape1);
el2.CalcShape(Tr.GetElement2IntPoint(), shape2);
el1.CalcShape(eip1, shape1);
el2.CalcShape(eip2, shape2);
// Interpolate elfun at the point
elfun1_mat.MultTranspose(shape1, funval1);
elfun2_mat.MultTranspose(shape2, funval2);
// Get the normal vector and the flux on the face
CalcOrtho(Tr.Jacobian(), nor);
if (1 == dim) {
nor(0) = 2*eip1.x - 1.0;
}
else {
CalcOrtho(Tr.Jacobian(), nor);
}
const double mcs = rsolver.Eval(funval1, funval2, nor, fluxN);
// Update max char speed
@@ -504,62 +546,147 @@ bool StateIsPhysical(const Vector &state, const int dim)
// Initial condition
void InitialCondition(const Vector &x, Vector &y)
{
MFEM_ASSERT(x.Size() == 2, "");
int dim = x.Size();
double radius = 0, Minf = 0, beta = 0;
if (problem == 1)
{
// "Fast vortex"
radius = 0.2;
Minf = 0.5;
beta = 1. / 5.;
}
else if (problem == 2)
{
// "Slow vortex"
radius = 0.2;
Minf = 0.05;
beta = 1. / 50.;
}
else
{
mfem_error("Cannot recognize problem."
"Options are: 1 - fast vortex, 2 - slow vortex");
}
if (dim == 1) {
const double xc = 0.0, yc = 0.0;
double rho;
double u;
double e;
// Nice units
const double vel_inf = 1.;
const double den_inf = 1.;
if (problem == 1) {
// Derive remainder of background state from this and Minf
const double pres_inf = (den_inf / specific_heat_ratio) * (vel_inf / Minf) *
(vel_inf / Minf);
const double temp_inf = pres_inf / (den_inf * gas_constant);
double xc = x[0]-0.5;
rho = 1.0;
u = 0.0;
e = 1.0+0.1*exp(-xc*xc);
double r2rad = 0.0;
r2rad += (x(0) - xc) * (x(0) - xc);
r2rad += (x(1) - yc) * (x(1) - yc);
r2rad /= (radius * radius);
}
else if (problem == 2) {
const double shrinv1 = 1.0 / (specific_heat_ratio - 1.);
u = 0.0;
double gamma = 1.4;
double gm1 = gamma -1.0;
const double velX = vel_inf * (1 - beta * (x(1) - yc) / radius * exp(
-0.5 * r2rad));
const double velY = vel_inf * beta * (x(0) - xc) / radius * exp(-0.5 * r2rad);
const double vel2 = velX * velX + velY * velY;
double rhoL = 1.0;
double pL = 1.0;
const double specific_heat = gas_constant * specific_heat_ratio * shrinv1;
const double temp = temp_inf - 0.5 * (vel_inf * beta) *
(vel_inf * beta) / specific_heat * exp(-r2rad);
double rhoR = 0.125;
double pR = 0.1;
const double den = den_inf * pow(temp/temp_inf, shrinv1);
const double pres = den * gas_constant * temp;
const double energy = shrinv1 * pres / den + 0.5 * vel2;
if (x[0] < 0.5) {
rho = rhoL;
e = 1./gm1*pL/rhoL;
}
else {
rho = rhoR;
e = 1./gm1*pR/rhoR;
}
}
else if (problem == 3) {
u = 0.0;
double gamma = 1.4;
double gm1 = gamma -1.0;
double rhoL = 1.0;
double pL = 1.0;
double rhoR = 0.125;
double pR = 0.1;
rho = rhoR;
e = 1./gm1*pR/rhoR;
if (x[0] > 0.3 && x[0] < 0.4) {
rho = rhoL;
e = 1./gm1*pL/rhoL;
}
if (x[0] > 0.5 && x[0] < 1.0) {
double xc = 0.75;
double x0 = x[0]-xc;
double a = 10.0;
double x1 = a*x0;
rho = rhoR +0.5*rhoL*exp(-x1*x1);
e = 1./gm1*pR/rhoL;
}
}
else {
printf("unknown problem!\n");
exit(1);
}
// if (x(0) < 0.5) {
// rho = 1.0;
// e = 1.05*(;
// }
int neq = 0;
y(neq++) = rho;
y(neq++) = rho * u;
y(neq++) = rho * e;
}
else {
MFEM_ASSERT(x.Size() == 2, "");
double radius = 0, Minf = 0, beta = 0;
if (problem == 1)
{
// "Fast vortex"
radius = 0.2;
Minf = 0.5;
beta = 1. / 5.;
}
else if (problem == 2)
{
// "Slow vortex"
radius = 0.2;
Minf = 0.05;
beta = 1. / 50.;
}
else
{
mfem_error("Cannot recognize problem."
"Options are: 1 - fast vortex, 2 - slow vortex");
}
const double xc = 0.0, yc = 0.0;
// Nice units
const double vel_inf = 1.;
const double den_inf = 1.;
// Derive remainder of background state from this and Minf
const double pres_inf = (den_inf / specific_heat_ratio) * (vel_inf / Minf) *
(vel_inf / Minf);
const double temp_inf = pres_inf / (den_inf * gas_constant);
double r2rad = 0.0;
r2rad += (x(0) - xc) * (x(0) - xc);
r2rad += (x(1) - yc) * (x(1) - yc);
r2rad /= (radius * radius);
const double shrinv1 = 1.0 / (specific_heat_ratio - 1.);
const double velX = vel_inf * (1 - beta * (x(1) - yc) / radius * exp(
-0.5 * r2rad));
const double velY = vel_inf * beta * (x(0) - xc) / radius * exp(-0.5 * r2rad);
const double vel2 = velX * velX + velY * velY;
const double specific_heat = gas_constant * specific_heat_ratio * shrinv1;
const double temp = temp_inf - 0.5 * (vel_inf * beta) *
(vel_inf * beta) / specific_heat * exp(-r2rad);
const double den = den_inf * pow(temp/temp_inf, shrinv1);
const double pres = den * gas_constant * temp;
const double energy = shrinv1 * pres / den + 0.5 * vel2;
int neq = 0;
y(neq++) = den;
y(neq++) = den * velX;
y(neq++) = den * velY;
y(neq++) = den * energy;
} // 2d
y(0) = den;
y(1) = den * velX;
y(2) = den * velY;
y(3) = den * energy;
}
+48
View File
@@ -0,0 +1,48 @@
#!/bin/bash
if [ $# -ne 2 ]; then
echo "Usage: generate-glvis-script <ncyc> <output-file-prefix>"
fi
ncyc=$1
prefix=$2
comp=0
ncycm1=$(( $ncyc - 1 ))
cat <<EOF > glvis-script
window 0 0 400 400
# Initial solution
solution soln-$comp.mesh soln-0-$comp.gf
# Setup the GLVis scene. Executed after pressing the space bar.
{
perspective off
viewcenter 0.2 0
valuerange 0.0 1.0
keys ca
autoscale off
}
# Take multiple screenshots. Executed after pressing space bar.
{
EOF
for i in `seq 0 $ncycm1`; do
if [ ! -f soln-$i.mesh ]; then
echo "The file soln-$i.mesh doesn't exist. Stopping."
exit 1
fi
if [ ! -f soln-$i-$comp.gf ]; then
echo "The file soln-$i-$comp.gf doesn't exist. Stopping."
exit 1
fi
ii=`printf %04d $i`
echo "solution soln-$i.mesh soln-$i-$comp.gf" >> glvis-script
#echo "valuerange 0.0 1.0" >> glvis-script
echo "screenshot $prefix-soln-$ii.png" >> glvis-script
done
echo "}" >> glvis-script
echo "% glvis -run glvis-script"
+11
View File
@@ -0,0 +1,11 @@
#!/bin/bash
rm -f tmp
for i in {0..19}; do
ii=`printf %04d $i`
echo "solution soln-$i.mesh soln-$i-0.gf" >> tmp
echo "valuerange 0.0 1.0" >> tmp
echo "screenshot greedy-soln-$ii.png" >> tmp
done
echo "output in ./tmp"
+32
View File
@@ -0,0 +1,32 @@
# Take err-N.dat files and create error plots for each cycle.
# Negative values are interpreted as refined regions and plotted in
# red.
import math
import matplotlib.pyplot as plt
for i in range(20):
print(f"{i}")
with open(f"err-{i}.dat") as f:
lines = f.readlines()
x = [float(line.split()[0]) for line in lines]
y = [float(line.split()[1]) for line in lines]
# errors in refined zones are marked as negative by convention
# from ex18. in order to detect "negative zero", we use the
# copysign method, which distinguishes negative zero from
# zero.
r = [(x,-y) for x,y in zip(x,y) if math.copysign(1, y) == -1.0]
xr,yr = zip(*r)
print(xr)
print(yr)
plt.scatter(x,y)
plt.scatter(xr,yr,c='r')
plt.title(f"Timestep {i}")
plt.xlabel("reference el")
plt.ylabel("L2 error")
plt.ylim(0,0.05)
#plt.show()
plt.savefig(f"opt-err-{i}.png",dpi=60)
plt.clf()
+19
View File
@@ -0,0 +1,19 @@
window 0 0 400 400
# Initial solution
solution soln-0.mesh soln-0-0.gf
# Setup the GLVis scene. Executed after pressing the space bar.
{
perspective off
# view 0 0
viewcenter 0.2 0
valuerange 0.0 1.0
# zoom 1.5
keys ca
}
# Take multiple screenshots. Executed after pressing the space bar.
{
#insert the screenshot commands here
}
+63
View File
@@ -0,0 +1,63 @@
#!/bin/bash
if [ $# -ne 1 ]; then
echo "Usage: ./make-periodic-mesh <NE>"
fi
NE=$1
NEm1=$(( $NE - 1 ))
NEm2=$(( $NE - 2 ))
filename="periodic-segment-$NE.mesh"
cat <<ENDHERE > $filename
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
#
dimension
1
# format: <attribute> <geometry type> <vertex 0> <vertex 1> ...
elements
ENDHERE
echo "$NE" >> $filename
for i in `seq 0 $NEm2`; do
echo "1 1 $i $((i+1))" >> $filename
done
echo "1 1 $((i+1)) 0" >> $filename
cat <<EOF >> $filename
boundary
0
vertices
$NE
nodes
FiniteElementSpace
FiniteElementCollection: L2_T1_1D_P1
VDim: 1
Ordering: 1
EOF
dx=`echo "1.0 / $NE" | bc -l`
for i in `seq 0 $NEm1`; do
p1=`echo "$i * $dx" | bc -l`
p2=`echo "$((i+1)) * $dx" | bc -l`
echo "$p1 $p2" >> $filename
done
+65
View File
@@ -0,0 +1,65 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
#
dimension
1
# format: <attribute> <geometry type> <vertex 0> <vertex 1> ...
elements
16
1 1 0 1
1 1 1 2
1 1 2 3
1 1 3 4
1 1 4 5
1 1 5 6
1 1 6 7
1 1 7 8
1 1 8 9
1 1 9 10
1 1 10 11
1 1 11 12
1 1 12 13
1 1 13 14
1 1 14 15
1 1 15 0
boundary
0
vertices
16
nodes
FiniteElementSpace
FiniteElementCollection: L2_T1_1D_P1
VDim: 1
Ordering: 1
0.0000 0.0625
0.0625 0.1250
0.1250 0.1875
0.1875 0.2500
0.2500 0.3125
0.3125 0.3750
0.3750 0.4375
0.4375 0.5000
0.5000 0.5625
0.5625 0.6250
0.6250 0.6875
0.6875 0.7500
0.7500 0.8125
0.8125 0.8750
0.8750 0.9375
0.9375 1.0000
+50
View File
@@ -0,0 +1,50 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
#
dimension
1
# format: <attribute> <geometry type> <vertex 0> <vertex 1> ...
elements
8
1 1 0 1
1 1 1 2
1 1 2 3
1 1 3 4
1 1 4 5
1 1 5 6
1 1 6 7
1 1 7 0
boundary
0
vertices
8
nodes
FiniteElementSpace
FiniteElementCollection: L2_T1_1D_P1
VDim: 1
Ordering: 1
0.000 0.125
0.125 0.250
0.250 0.375
0.375 0.500
0.500 0.625
0.625 0.750
0.750 0.875
0.875 1.000
+43
View File
@@ -0,0 +1,43 @@
#!/bin/bash
# sod 5 regrids
options="-dt 0.01 --cfl-number -1 " # fixed timestep
options+="--regrid-period 4 " # regrid period
options+="--problem 2 " # Sod problem
options+="--order 0 " # 0th order DG
options+="--refine 0 " # no initial uniform refinement
options+="--t-final 0.20 "
# create reference solution on 16 element mesh
./ex18 $options -m periodic-segment-20.mesh
./save-reference
ne=10
nem1=$((ne-1))
echo "" > err-results.dat
for i1 in $(seq 0 $nem1); do
for i2 in $(seq 0 $nem1); do
for i3 in $(seq 0 $nem1); do
for i4 in $(seq 0 $nem1); do
for i5 in $(seq 0 $nem1); do
dir="seq-$i1$i2$i3$i4$i5"
mkdir $dir
cd $dir
ln -s ../reference.mesh .
ln -s ../reference-rho.gf .
ln -s ../reference-rho-u.gf .
ln -s ../reference-rho-e.gf .
echo "running $i1$i2$i3$i4$i5"
seq="$i1 $i2 $i3 $i4 $i5"
cmd="../ex18 -rseq \"$seq\" $options -m ../periodic-segment-10.mesh | grep err | awk \"{print \$2}\""
echo "$cmd" > runcode
err=$( source runcode )
cd ..
echo "$i1 $i2 $i3 $i4 $i5 $err" >> err-results.dat
done
done
done
done
done
+16
View File
@@ -0,0 +1,16 @@
#!/bin/bash
# The final time is the reference solution
mv vortex.mesh reference.mesh
mv vortex-0-final.gf reference-rho.gf
mv vortex-1-final.gf reference-rho-u.gf
mv vortex-2-final.gf reference-rho-e.gf
# Save the timesteps as well for errors
for i in {0..19}
do
mv soln-$i.mesh reference-$i.mesh
mv soln-$i-0.gf reference-$i-0.gf
mv soln-$i-1.gf reference-$i-1.gf
mv soln-$i-2.gf reference-$i-2.gf
done
+2 -2
View File
@@ -3495,8 +3495,6 @@ void Mesh::SetMeshGen()
mesh_geoms |= (1 << Geometry::TETRAHEDRON);
case Element::TRIANGLE:
mesh_geoms |= (1 << Geometry::TRIANGLE);
case Element::SEGMENT:
mesh_geoms |= (1 << Geometry::SEGMENT);
case Element::POINT:
mesh_geoms |= (1 << Geometry::POINT);
meshgen |= 1;
@@ -3508,6 +3506,8 @@ void Mesh::SetMeshGen()
mesh_geoms |= (1 << Geometry::SQUARE);
mesh_geoms |= (1 << Geometry::SEGMENT);
mesh_geoms |= (1 << Geometry::POINT);
case Element::SEGMENT:
mesh_geoms |= (1 << Geometry::SEGMENT);
meshgen |= 2;
break;
+13
View File
@@ -4253,6 +4253,19 @@ void NCMesh::GetPointMatrix(Geometry::Type geom, const char* ref_path,
pm = PointMatrix(mid12, mid20, mid01);
}
}
else if (geom == Geometry::SEGMENT)
{
Point mid01(pm(0), pm(1));
if (child == 0)
{
pm = PointMatrix(pm(0), mid01);
}
else if (child == 1)
{
pm = PointMatrix(mid01, pm(1));
}
}
}
// write the points to the matrix