Beispiel #1
0
int main(int argc, char ** argv)
{
	if( argc < 3 )
	{
		std::cout << "Usage: " << argv[0] << " mesh mesh_out" << std::endl;
		return 0;
	}
	
	Mesh * m = new Mesh;
	m->SetFileOption("VERBOSITY","2");
	try{m->Load(argv[1]);} catch(...) { std::cout << "Cannot load the mesh " << argv[1] << std::endl; return -1;}

  Mesh::GeomParam t;
	t[MEASURE] = CELL | FACE;
	t[ORIENTATION] = FACE;
	t[NORMAL] = FACE;
	//t[BARYCENTER] = CELL;
	t[CENTROID] = CELL | FACE;
	m->AssignGlobalID(CELL|FACE);
	m->PrepareGeometricData(t);

	double max[3] = {-1.0e20, -1.0e20, -1.0e20}, min[3] = {1.0e20,1.0e20,1.0e20};
  Storage::real c[3] = {0,0,0}, nrm[3] = {0,0,0};
	for(Mesh::iteratorNode it = m->BeginNode(); it != m->EndNode(); ++it)
	{
		it->Centroid(c);
		if( c[0] > max[0] ) max[0] = c[0];
		if( c[1] > max[1] ) max[1] = c[1];
		if( c[2] > max[2] ) max[2] = c[2];
		if( c[0] < min[0] ) min[0] = c[0];
		if( c[1] < min[1] ) min[1] = c[1];
		if( c[2] < min[2] ) min[2] = c[2];
	}

	if( max[0] <= min[0] ) {std::cout << "strange X " << min[0] << ":" << max[0] << std::endl; return -1;}
	if( max[1] <= min[1] ) {std::cout << "strange Y " << min[1] << ":" << max[1] << std::endl; return -1;}
	if( max[2] <= min[2] ) 
  {
    //2d mesh
    if( m->GetDimensions() == 3 )
    {
      //offset from z-plane
      min[2] -= 0.0001;
      max[2] += 0.0001; 
    }
    else
    {
      min[2] = -0.0001;
      max[2] = +0.0001;
    }
  }

  std::cout << "Mesh bounds: " << min[0] << ":" << max[0] << " " << min[1] << ":" << max[1] << " " << min[2] << ":" << max[2] << std::endl;

	Tag material;
	if( m->HaveTag("PERM") ) m->DeleteTag(m->GetTag("PERM"));

	

	Tag vel = m->CreateTag("REFERENCE_VELOCITY",DATA_REAL,CELL,NONE,3);
  Tag force = m->CreateTag("FORCE",DATA_REAL,CELL,NONE,1);
  Tag tensor = m->CreateTag("PERM",DATA_REAL,CELL,NONE,6);
  Tag solution_val = m->CreateTag("REFERENCE_SOLUTION",DATA_REAL,CELL|FACE|EDGE|NODE,NONE,1);
  Tag solution_flux = m->CreateTag("REFERENCE_FLUX",DATA_REAL,FACE,FACE,1);
	Tag saddle_val = m->CreateTag("SADDLE_SOLUTION",DATA_REAL,CELL,NONE,4);
  Tag saddle_flux = m->CreateTag("SADDLE_FLUX",DATA_REAL,FACE,NONE,4);
  Tag bndcond = m->CreateTag("BOUNDARY_CONDITION",DATA_REAL,FACE|EDGE,FACE|EDGE,3);

    {
        Storage::bulk_array name = m->self()->BulkArray(m->CreateTag("PROBLEMNAME",DATA_BULK,MESH,NONE));
        name.replace(name.begin(),name.end(),problem_name.begin(),problem_name.end());
    }

  
	for(Mesh::iteratorElement it = m->BeginElement(CELL|FACE|EDGE|NODE); it != m->EndElement(); ++it)
	{

    it->Centroid(c);
    if( it->GetElementType() == CELL )
    {
      Storage::real_array perm = it->RealArray(tensor);
      perm[0] = 1.5;
      perm[1] = 0.5;
      perm[2] = 0.0;
      perm[3] = 1.5;
      perm[4] = 0.0;
      perm[5] = 1.0;
    }

		
    

    
    Storage::real x = c[0];//(c[0]-min[0])/(max[0]-min[0]);
		Storage::real y = c[1];//(c[1]-min[1])/(max[1]-min[1]);
    Storage::real z = c[2];//(c[2]-min[2])/(max[2]-min[2]);
    Storage::real sol = 16.0*(1-x)*y*(1-y);
    Storage::real flux;

    Storage::real dsolx = 16*(y-1)*y;
    Storage::real dsoly = 16*(x-1)*(2*y-1);

    if( it->GetElementType() == CELL )
      it->Real(force) = -16*(2*y+3*x-4);

    it->Real(solution_val) = sol;
		
		if( it->GetElementType() == CELL )
		{
		it->RealArray(vel)[0] = 1.5*dsolx + 0.5*dsoly;
		it->RealArray(vel)[1] = 0.5*dsolx + 1.5*dsoly;
		it->RealArray(vel)[2] = 0;
			
			it->RealArray(saddle_val)[0] = 1.5*dsolx + 0.5*dsoly;
			it->RealArray(saddle_val)[1] = 0.5*dsolx + 1.5*dsoly;
			it->RealArray(saddle_val)[2] = 0;
			it->RealArray(saddle_val)[3] = sol;
		}
    
    if( it->GetElementType() == FACE )
    {
      it->getAsFace()->UnitNormal(nrm);
      flux = (1.5*nrm[0]+0.5*nrm[1])*dsolx + (0.5*nrm[0]+1.5*nrm[1])*dsoly;
      
      if( !(z < eps || z > 1.0-eps ) )
      {
        it->Real(solution_flux) = -flux;

        if( it->getAsFace()->Boundary() )
        {
          Storage::real_array bc = it->RealArray(bndcond);
          bc[0] = 1.0;
          bc[1] = 0.0;
          bc[2] = sol;
        }
      }
		
		it->RealArray(saddle_flux)[0] = sol*(1.5*nrm[0]+0.5*nrm[1]);
		it->RealArray(saddle_flux)[1] = sol*(0.5*nrm[0]+1.5*nrm[1]);
		it->RealArray(saddle_flux)[2] = sol*nrm[2];
		it->RealArray(saddle_flux)[3] = flux;
    }
    if( it->GetElementType() == EDGE )
    {
      if( it->Boundary() )
      {
        Storage::real_array bc = it->RealArray(bndcond);
        bc[0] = 1.0;
        bc[1] = 0.0;
        bc[2] = sol;
      }
    }
  }

  std::cout << "Saving output to " << argv[2] << std::endl;

	m->Save(argv[2]);

	delete m;
}
Beispiel #2
0
int main(int argc, char *argv[]) 
{

	if (argc < 2)
	{
		std::cout << "Usage: " << argv[0] << " nx|grid_name [alpha=0.4] [outer_boundary_pressure=0.0] [inner_boundary_pressure=1.0] [cut_grid=1] [is2d=1]" << std::endl;
		return -1;
	}

	Mesh * mesh;
	double alpha=0.2;
	double h;
	double outer_boundary_pressure = 0.0;
	double inner_boundary_pressure = 1.0;
	int cut_grid = 1;
	int is2d = 0;
	int n = 20 + 1;

	mesh = new Mesh();

	if (argc > 1) 
	{
		if( atoi(argv[1]) )
		{
			n = atoi(argv[1])+1;
			h = 1.0 / (n-1);
			std::cout << "Mesh: cube " << n << std::endl;
		}
		else
		{
			mesh->Load(argv[1]);
			std::cout << "Mesh: " << argv[1] << std::endl;
			n = 0;
		}

	}

	std::cout << "Mesh radius: " << h << std::endl;
	if( argc > 2 )
		alpha = atof(argv[2]);

	std::cout << "Alpha: " << alpha << std::endl;

	if( argc > 3 )
		outer_boundary_pressure = atof(argv[3]);

	if( argc > 4 )
		inner_boundary_pressure = atof(argv[4]);

	std::cout << "Boundaries: " << outer_boundary_pressure << " " << inner_boundary_pressure << std::endl;

	if( argc > 5 )
		cut_grid = atoi(argv[5]);

	if( cut_grid )
		std::cout << "Cutting center of the grid." << std::endl;

	if( argc > 6 )
		is2d = atoi(argv[6]);

	if( is2d )
		std::cout << "Using 2d setup" << std::endl;
	else
		std::cout << "Using 3d setup" << std::endl;

	double ratio = 1000;
	if( argc > 7 )
		ratio = atof(argv[7]);

	std::cout << "Anisotropy ratio: " << ratio << std::endl;


	srand(0);//(unsigned)time(NULL));

	if( n )
	{
		for (int i = 0; i < n; i++) 
		{
			for (int j = 0; j < n; j++) 
			{
				for (int k = 0; k < n; k++) 
				{
					Storage::real xyz[3];
					bool mark = false;
					xyz[0] = i * 1.0 / (n - 1);
					xyz[1] = j * 1.0 / (n - 1);
					xyz[2] = k * 1.0 / (n - 1);
					Node c = mesh->CreateNode(xyz);
					if (c->LocalID() != V_ID(i, j, k)) printf("v_id = %d, [i,j,k] = %d\n", c->LocalID(), V_ID(i, j, k));
				}
			}
		}


		const INMOST_DATA_INTEGER_TYPE nvf[24] = { 2, 3, 1, 0, 4, 5, 7, 6, 0, 1, 5, 4, 3, 2, 6, 7, 2, 0, 4, 6, 1, 3, 7, 5 };
		const INMOST_DATA_INTEGER_TYPE numnodes[6] = { 4, 4, 4, 4, 4, 4 };
		for (int i = 1; i < n; i++) 
		{
			for (int j = 1; j < n; j++) 
			{
				for (int k = 1; k < n; k++) 
				{

					ElementArray<Node> verts(mesh,8); 
					verts[0] = mesh->NodeByLocalID(V_ID(i - 1, j - 1, k - 1));
					verts[1] = mesh->NodeByLocalID(V_ID(i - 0, j - 1, k - 1));
					verts[2] = mesh->NodeByLocalID(V_ID(i - 1, j - 0, k - 1));
					verts[3] = mesh->NodeByLocalID(V_ID(i - 0, j - 0, k - 1));
					verts[4] = mesh->NodeByLocalID(V_ID(i - 1, j - 1, k - 0));
					verts[5] = mesh->NodeByLocalID(V_ID(i - 0, j - 1, k - 0));
					verts[6] = mesh->NodeByLocalID(V_ID(i - 1, j - 0, k - 0));
					verts[7] = mesh->NodeByLocalID(V_ID(i - 0, j - 0, k - 0));

					mesh->CreateCell(verts,nvf,numnodes,6);
				}
			}
		}
	}


	if( cut_grid )
	{
		for (Mesh::iteratorCell it = mesh->BeginCell(); it != mesh->EndCell(); ++it)
		{
			Storage::real cnt[3];
			it->Centroid(cnt);
			if( cnt[0] > 0.25 && cnt[0] < 0.75 && cnt[1] > 0.25 && cnt[1] < 0.75 )
				it->Delete();
			
		}

		for (Mesh::iteratorElement it = mesh->BeginElement(FACE|EDGE|NODE); it != mesh->EndElement(); ++it)
			if( it->nbAdjElements(CELL) == 0 ) it->Delete();
	}

	if( alpha > 0.0 ) //skewness
	{
		const double eps = 1.0e-6;
		for( Mesh::iteratorNode it = mesh->BeginNode(); it != mesh->EndNode(); ++it)
		{
			Storage::real_array coords = it->Coords();
			Storage::real h = 1.0e20;

			ElementArray<Cell> it_cells = it->getCells();

			for(int k = 0; k < it_cells.size(); ++k)
			{
				Storage::real maxmin[6];
				maxmin[0] = -1e20;
				maxmin[1] = 1e20;
				maxmin[2] = -1e20;
				maxmin[3] = 1e20;
				ElementArray<Node> nodes = it_cells[k].getNodes();
				for (ElementArray<Node>::iterator it = nodes.begin(); it != nodes.end(); it++)
				{
					Storage::real_array cc = it->Coords();
					for (int i = 0; i < (int)cc.size(); i++) 
					{
						if (maxmin[2 * i + 0] < cc[i]) maxmin[2 * i + 0] = cc[i]; //max
						if (maxmin[2 * i + 1] > cc[i]) maxmin[2 * i + 1] = cc[i]; //min
					}
				}
				h = std::min(h,sqrt((maxmin[2]-maxmin[3])*(maxmin[2]-maxmin[3])+(maxmin[0]-maxmin[1])*(maxmin[0]-maxmin[1])));
			}
			if( coords[0] > eps && coords[0] < 1.0-eps && coords[1] > eps && coords[1] < 1.0-eps )
			{
				if( !(coords[0] > 4.0/9.0-eps && coords[0] < 5.0/9.0+eps && coords[1] > 4.0/9.0-eps && coords[1] < 5.0/9.0+eps) )
				{
					coords[0] += alpha*h*(2.0*rand()/RAND_MAX-1.0);
					coords[1] += alpha*h*(2.0*rand()/RAND_MAX-1.0);
				}
			}
		}
	}

	for( Mesh::iteratorNode it = mesh->BeginNode(); it != mesh->EndNode(); ++it)
	{
		Storage::real_array coords = it->Coords();
		coords[0] = 2*coords[0]-1;
		coords[1] = 2*coords[1]-1;
	}

	mesh->ReorderEmpty(CELL|FACE|EDGE|NODE);

	{ // Prepare geometrical data on the mesh.
		Mesh::GeomParam table;
		table[CENTROID]    = CELL | FACE; //Compute averaged center of mass
		table[NORMAL]      = FACE;        //Compute normals
		table[ORIENTATION] = FACE;        //Check and fix normal orientation
		table[MEASURE]     = CELL | FACE; //Compute volumes and areas
		//table[BARYCENTER]  = CELL | FACE; //Compute volumetric center of mass
		mesh->RemoveGeometricData(table);
		mesh->PrepareGeometricData(table); //Ask to precompute the data
	}

	printf("nodes: %d edges: %d faces: %d cells: %d\n", mesh->NumberOfNodes(), mesh->NumberOfEdges(), mesh->NumberOfFaces(), mesh->NumberOfCells());


	{
		Storage::bulk_array name = mesh->self()->BulkArray(mesh->CreateTag("PROBLEMNAME",DATA_BULK,MESH,NONE));
		name.replace(name.begin(),name.end(),problem_name.begin(),problem_name.end());
	}

	Tag bndcond = mesh->CreateTag("BOUNDARY_CONDITION",DATA_REAL,FACE,FACE,3);
	Tag velocity = mesh->CreateTag("VELOCITY",DATA_REAL,FACE,NONE,1);
	Tag reaction = mesh->CreateTag("REACTION",DATA_REAL,CELL,NONE,1);
	Tag tensor = mesh->CreateTag("PERM", DATA_REAL, CELL, NONE, 1);
	Tag force = mesh->CreateTag("FORCE",DATA_REAL,CELL,NONE,1);
	Tag vel3 = mesh->CreateTag("VELVEC",DATA_REAL,CELL,NONE,3);
	Tag refsol = mesh->CreateTag("REFERENCE_SOLUTION",DATA_REAL,CELL,NONE,1);
	Tag refflux = mesh->CreateTag("REFERENCE_FLUX",DATA_REAL,FACE,NONE,1);
	Tag zone = mesh->CreateTag("ZONE",DATA_INTEGER,CELL,NONE,1);
	int numinner = 0, numouter = 0;
	int numinnern = 0, numoutern = 0;
	const double eps = 1.0e-6;
	const double mu = 1.0e-3;
	const double velmult = 1;
	for(Mesh::iteratorFace it = mesh->BeginFace(); it != mesh->EndFace(); ++it) 
	{
		Storage::real cnt[3], nrm[3];
		it->Centroid(cnt);
		it->UnitNormal(nrm);
		Storage::real x = cnt[0];
		Storage::real y = cnt[1];
		Storage::real z = cnt[2];
		Storage::real r = sqrt(x*x+y*y);
		Storage::real theta = atan2(y,x);//+pi;
		Storage::real sol, diff, flux, velnrm, dsolx, dsoly;
		Storage::real vel[3] = {-y/(r*r)*velmult,x/(r*r)*velmult,0.0};

		if( theta < 0 ) theta = 2*pi + theta;
		
		velnrm = nrm[0]*vel[0] + nrm[1]*vel[1] + nrm[2]*vel[2];

		if( theta < pi )
		{
			diff = pi;
			sol = (theta-pi)*(theta-pi);
			dsolx = -2*y*(theta-pi)/(r*r);
			dsoly = 2*x*(theta-pi)/(r*r);
			flux = velnrm*sol - diff*(dsolx*nrm[0] + dsoly*nrm[1]);
		}
		else
		{
			diff = 0;
			sol = 3*pi*(theta-pi);
			flux = velnrm*sol;
		}
		
		it->Real(refflux) = flux;
		it->Real(velocity) = velnrm;

		if( it->Boundary() && z > 0+eps && z < 1-eps)
		{
			Storage::real_array bc = it->RealArray(bndcond);
			bc[0] = 1;
			bc[1] = 0;
			bc[2] = sol;
		}
	}
	std::cout << "Outer faces " << numouter << " inner faces " << numinner << std::endl;
	std::cout << "Outer nodes " << numoutern << " inner nodes " << numinnern << std::endl;

	
	
	for (Mesh::iteratorCell it = mesh->BeginCell(); it != mesh->EndCell(); ++it)
	{
		Storage::real cnt[3];
		it->Centroid(cnt);
		Storage::real f = 0;
		Storage::real x = cnt[0];
		Storage::real y = cnt[1];
		Storage::real r = sqrt(x*x+y*y);
		Storage::real theta = atan2(y,x);//+pi;
		Storage::real sol, diff;
		Storage::real vel[3] = {-y/(r*r)*velmult,x/(r*r)*velmult,0.0};

		if( theta < 0 ) theta = 2*pi + theta;
		
		it->Centroid(cnt);
		if( theta < pi )
		{
			diff = pi;
			//diff = 0;
			sol = (theta-pi)*(theta-pi);
			f = mu*sol + 2*(theta-pi)/(r*r)*velmult - diff*2/(r*r);
			
			it->Integer(zone) = 0;
		}
		else 
		{
			diff = 0;
			sol = 3*pi*(theta-pi);
			f = mu*sol + 3*pi/(r*r)*velmult;
			
			it->Integer(zone) = 1;
		}

		it->Real(force) = f;
		it->Real(reaction) = mu;
		it->Real(refsol) = sol;
		it->Real(tensor) = diff;

		Storage::real_array svel = it->RealArray(vel3);
		svel[0] = vel[0];
		svel[1] = vel[1];
		svel[2] = vel[2];
	}

	printf("I'm ready!\n");

	//mesh->Save("grid.vtk");
	mesh->Save("grid_out.pmf");
	//mesh->Save("grid.gmv");

	printf("File written!\n");

	delete mesh;
	return 0;
}
Beispiel #3
0
int main(int argc, char ** argv)
{
	if( argc < 3 )
	{
		std::cout << "Usage: " << argv[0] << " mesh mesh_out [sigma:0.2 incline:1 y_low:0.25 y_high:0.5]" << std::endl;
		return 0;
	}
	
	Mesh * m = new Mesh;
	m->SetFileOption("VERBOSITY","2");
	try{m->Load(argv[1]);} catch(...) { std::cout << "Cannot load the mesh " << argv[1] << std::endl; return -1;}
	
	Storage::real sigma = 0.2, y_low = 0.25, y_high = 0.5, alpha = 0.15;
	
	if( argc > 3 ) sigma = atof(argv[3]);
	
	//for(Mesh::iteratorTag t = m->BeginTag(); t != m->EndTag(); ++t)
	//  if( t->GetTagName().substr(0,9) == "GEOM_UTIL" ) m->DeleteTag(*t);
	
	if( argc <= 4 || (argc > 4 && atoi(argv[4])) )
	{
		double max[3] = {-1.0e20, -1.0e20, -1.0e20}, min[3] = {1.0e20,1.0e20,1.0e20};
		for(Mesh::iteratorNode it = m->BeginNode(); it != m->EndNode(); ++it)
		{
			Storage::real_array c = it->Coords();
			if( c[0] > max[0] ) max[0] = c[0];
			if( c[1] > max[1] ) max[1] = c[1];
			if( c[2] > max[2] ) max[2] = c[2];
			if( c[0] < min[0] ) min[0] = c[0];
			if( c[1] < min[1] ) min[1] = c[1];
			if( c[2] < min[2] ) min[2] = c[2];
		}

		std::cout << "You asked to incline the grid to honour discontinuities" << std::endl;
		std::cout << "and I assume that the initial grid is rectangular." << std::endl;
		for(Mesh::iteratorNode it = m->BeginNode(); it != m->EndNode(); ++it)
		{
			
			Storage::real_array c = it->Coords();
			Storage::real x = c[0];
			Storage::real y = c[1];
			Storage::real d = 0.0;
			Storage::real y1 = sigma*(x-0.5)+0.475;
			Storage::real y2 = sigma*(x-0.5)+0.475+0.05;
			if( y <= y_low ) d = y/y_low*(y1-y_low);
			else if( y >= y_low && y <= y_high ) d = (y1-y_low) + (y-y_low)/(y_high-y_low)*((y2-y_high)-(y1-y_low));
			else d = (1-(y-y_high)/(1-y_high))*(y2-y_high);
			c[1] += d;

			
		}


		//introduce skewness
		/*
		for(Mesh::iteratorNode it = m->BeginNode(); it != m->EndNode(); ++it)
		{
			Storage::real_array c = it->Coords();
			Storage::real x = c[0];
			Storage::real y = c[1];
			Storage::real y1 = sigma*(x-0.5)+0.475;
			Storage::real y2 = sigma*(x-0.5)+0.475+0.05;
			Storage::real rndx = (rand()*1.0/RAND_MAX*2-1);
			Storage::real rndy = (rand()*1.0/RAND_MAX*2-1);
			Storage::real h = 1.0e20;

			ElementArray<Cell> it_cells = it->getCells();

			for(int k = 0; k < it_cells.size(); ++k)
			{
				Storage::real maxmin[6];
				maxmin[0] = -1e20;
				maxmin[1] = 1e20;
				maxmin[2] = -1e20;
				maxmin[3] = 1e20;
				ElementArray<Node> nodes = it_cells[k].getNodes();
				for (ElementArray<Node>::iterator it = nodes.begin(); it != nodes.end(); it++)
				{
					Storage::real_array cc = it->Coords();
					for (int i = 0; i < (int)cc.size(); i++) 
					{
						if (maxmin[2 * i + 0] < cc[i]) maxmin[2 * i + 0] = cc[i]; //max
						if (maxmin[2 * i + 1] > cc[i]) maxmin[2 * i + 1] = cc[i]; //min
					}
				}
				h = std::min(h,sqrt((maxmin[2]-maxmin[3])*(maxmin[2]-maxmin[3])+(maxmin[0]-maxmin[1])*(maxmin[0]-maxmin[1])));
			}


			if( fabs(y-y1) > 1.0e-9 && fabs(y-y2) > 1.0e-9 && x > 0 && x < 1 && y > 0 && y < 1 )
			{
				c[0] += rndx*h*alpha;
				c[1] += rndy*h*alpha;
			}
		}
		*/
	}
	
	Mesh::GeomParam t;
	t[MEASURE] = CELL | FACE;
	t[ORIENTATION] = FACE;
	t[NORMAL] = FACE;
	//t[BARYCENTER] = CELL;
	t[CENTROID] = CELL | FACE | EDGE | NODE;
	m->AssignGlobalID(CELL|FACE);
	//m->RemoveGeometricData(t);
	m->PrepareGeometricData(t);
	
	double max[3] = {-1.0e20, -1.0e20, -1.0e20}, min[3] = {1.0e20,1.0e20,1.0e20};
	Storage::real c[3] = {0,0,0}, nrm[3] = {0,0,0};
	for(Mesh::iteratorNode it = m->BeginNode(); it != m->EndNode(); ++it)
	{
		it->Centroid(c);
		if( c[0] > max[0] ) max[0] = c[0];
		if( c[1] > max[1] ) max[1] = c[1];
		if( c[2] > max[2] ) max[2] = c[2];
		if( c[0] < min[0] ) min[0] = c[0];
		if( c[1] < min[1] ) min[1] = c[1];
		if( c[2] < min[2] ) min[2] = c[2];
	}
	
	if( max[0] <= min[0] ) {std::cout << "strange X " << min[0] << ":" << max[0] << std::endl; return -1;}
	if( max[1] <= min[1] ) {std::cout << "strange Y " << min[1] << ":" << max[1] << std::endl; return -1;}
	if( max[2] <= min[2] )
	{
		//2d mesh
		if( m->GetDimensions() == 3 )
		{
			//offset from z-plane
			min[2] -= 0.0001;
			max[2] += 0.0001;
		}
		else
		{
			min[2] = -0.0001;
			max[2] = +0.0001;
		}
	}
	
	std::cout << "Mesh bounds: " << min[0] << ":" << max[0] << " " << min[1] << ":" << max[1] << " " << min[2] << ":" << max[2] << std::endl;
	
	if( m->HaveTag("PERM") ) m->DeleteTag(m->GetTag("PERM"));
	if( m->HaveTag("MATERIAL") ) m->DeleteTag(m->GetTag("MATERIAL"));
	
	Tag rvel = m->CreateTag("REFERENCE_VELOCITY",DATA_REAL,CELL,NONE,3);
	Tag material = m->CreateTag("MATERIAL",DATA_INTEGER,CELL|EDGE|FACE|NODE,NONE,1);
	Tag tensor = m->CreateTag("PERM",DATA_REAL,CELL,NONE,3);
	Tag solution_val = m->CreateTag("REFERENCE_SOLUTION",DATA_REAL,CELL|FACE|EDGE|NODE,NONE,1);
	Tag saddle_val = m->CreateTag("SADDLE_SOLUTION",DATA_REAL,CELL,NONE,4);
	Tag solution_flux = m->CreateTag("REFERENCE_FLUX",DATA_REAL,FACE,FACE,1);
	Tag saddle_flux = m->CreateTag("SADDLE_FLUX",DATA_REAL,FACE,NONE,4);
	Tag bndcond = m->CreateTag("BOUNDARY_CONDITION",DATA_REAL,FACE|EDGE|NODE,FACE|EDGE|NODE,3);
	Tag velocity, force;

	{
		Storage::bulk_array name = m->self()->BulkArray(m->CreateTag("PROBLEMNAME",DATA_BULK,MESH,NONE));
		name.replace(name.begin(),name.end(),problem_name.begin(),problem_name.end());
	}
	
	
	double velmult = 0.0;
	
	if( velmult )
	{
		force = m->CreateTag("FORCE",DATA_REAL,CELL,NONE,1);
		velocity = m->CreateTag("VELOCITY",DATA_REAL,FACE,NONE,1);
	}

	
	for(Mesh::iteratorElement it = m->BeginElement(CELL|FACE|EDGE|NODE); it != m->EndElement(); ++it)
	{
		it->Centroid(c);
		Storage::real x = c[0];//(c[0]-min[0])/(max[0]-min[0]);
		Storage::real y = c[1];//(c[1]-min[1])/(max[1]-min[1]);
		Storage::real z = c[2];//(c[2]-min[2])/(max[2]-min[2]);
		Storage::real r = 1;//sqrt((x-0.5)*(x-0.5)+(y-0.5)*(y-0.5));
		//Storage::real vel[3] = {-(y-0.5)/(r*r)*velmult,(x-0.5)/(r*r)*velmult,0.0};
		Storage::real vel[3] = {-0.5*velmult,velmult,0.0};

		
		
		int zone = 0;
		
		double phi1 = y - sigma*(x-0.5) - 0.475;
		double phi2 = phi1 - 0.05;
		double alpha;
		
		if( phi1 < 0 ) zone = 1;
		else if( phi1 >= 0 && phi2 < 0 ) zone = 2;
		else zone = 3;
		//else printf("%s:%d oops!\n",__FILE__,__LINE__);
		
		it->IntegerDF(material) = zone;
		
		Storage::real sol, dsolx, dsoly;
		Storage::real flux;
		
		if( zone == 2 )
		{
			alpha = 0.01;
		}
		else
		{
			alpha = 1;
		}
		sol = 0;
		if( zone == 1 )
		{
			sol = -phi1;
			dsolx = sigma;
			dsoly = -1;
		}
		else if( zone == 2 )
		{
			sol = -phi1/0.01;
			dsolx = sigma/0.01;
			dsoly = -1/0.01;
		}
		else if( zone == 3 )
		{
			sol = -phi2 - 0.05/0.01;
			dsolx = sigma;
			dsoly = -1;
		}
		
		sol += 6; //pick solution up for positivity
		
		Storage::real K[6] =
		{
			alpha,
			0.0,
			0.0,
			alpha,
			0,
			1
		};
		
		
		if( it->GetElementType() == CELL )
		{
			Storage::real_array perm = it->RealArray(tensor);
			perm[0] = alpha;
			perm[1] = alpha;
			perm[2] = 1;
		}
		
		
		it->Real(solution_val) = sol;

		if( it->GetElementType() == CELL && velmult )
		{
			it->Real(force) = (dsolx*vel[0] + dsoly*vel[1]);
		}
		
		if( it->GetElementType() == CELL )
		{
			it->RealArray(rvel)[0] = dsolx*alpha;
			it->RealArray(rvel)[1] = dsoly*alpha;
			it->RealArray(rvel)[2] = 0;
			
			it->RealArray(saddle_val)[0] = dsolx*alpha;
			it->RealArray(saddle_val)[1] = dsoly*alpha;
			it->RealArray(saddle_val)[2] = 0;
			it->RealArray(saddle_val)[3] = sol;
		}
		
		if( it->GetElementType() == FACE )
		{
			it->getAsFace()->UnitNormal(nrm);

			double adv_flux = 0;

			if( velmult )
			{
				double nvel = vel[0]*nrm[0] + vel[1]*nrm[1] + vel[2]*nrm[2];
				it->Real(velocity) = nvel;
				adv_flux = sol*nvel;
			}
			
			
			flux = -((K[0]*nrm[0]+K[1]*nrm[1])*dsolx + (K[1]*nrm[0]+K[3]*nrm[1])*dsoly) + adv_flux;
			
			it->RealArray(saddle_flux)[0] = sol*(K[0]*nrm[0]+K[1]*nrm[1]);
			it->RealArray(saddle_flux)[1] = sol*(K[1]*nrm[0]+K[3]*nrm[1]);
			it->RealArray(saddle_flux)[2] = sol*nrm[2];
			it->RealArray(saddle_flux)[3] = -flux;
			
			if( !(z < eps || z > 1.0-eps ) )
			{
				it->Real(solution_flux) = flux;
				
				if( it->getAsFace()->Boundary() )
				{
					Storage::real_array bc = it->RealArray(bndcond);
					bc[0] = 1.0;
					bc[1] = 0.0;
					bc[2] = sol;
				}
			}

			
		}
		if( it->GetElementType() & (EDGE | NODE) )
		{
			if( (x < eps || x > 1.0-eps || y < eps || y > 1.0-eps) )
			{
				if( it->Boundary() )
				{
					Storage::real_array bc = it->RealArray(bndcond);
					bc[0] = 1.0;
					bc[1] = 0.0;
					bc[2] = sol;
				}
			}
		}
	}
	
	std::cout << "Saving output to " << argv[2] << std::endl;
	
	m->Save(argv[2]);
	
	delete m;
}