int main()
{
	ElementArray elementArray;
	
	/////////////////////////////////////////////////////
	// 데이터 구성
	/////////////////////////////////////////////////////
	size_t elementSize, intervalSize;
	cin >> elementSize >> intervalSize;

	elementArray.assign(elementSize, 0);
	
	// 각 원소 입력
	for (size_t i = 0; i < elementArray.size(); i++)
		cin >> elementArray[i];

	/////////////////////////////////////////////////////
	// 각 구간별 최대값 계산 & 출력
	/////////////////////////////////////////////////////
	for (size_t i = 0; i < intervalSize; i++)
	{
		size_t begin;
		size_t end;

		cin >> begin >> end;
		cout << elementArray.calcMax(begin - 1, end) << endl;
	}

#ifdef _WIN32
	system("pause");
#endif
	return 0;
}
Ejemplo n.º 2
0
TEST(ArrayTest, testConstruction)
{

	// fundamental type
	typedef Poco::Array<float,6> FloatArray;
	FloatArray a = { { 42.f } };

	for (unsigned i=1; i<a.size(); ++i) {
		a[i] = a[i-1]+1.f;
	}

	// copy constructor and assignment operator
	FloatArray b(a);
	FloatArray c;
	c = a;
	EXPECT_TRUE (a==b && a==c);

	typedef Poco::Array<double,6> DArray;
	typedef Poco::Array<int,6> IArray;
	IArray ia = {{1, 2, 3, 4, 5, 6 }};
	DArray da;
	da = ia;
	da.assign(42);

	// user-defined type
	typedef Poco::Array<Element,10> ElementArray;
	ElementArray g;

	for (unsigned i=0; i<g.size(); ++i) {
		g[i]._data = i;
	}

	for (unsigned i=0; i<g.size(); ++i) {
		EXPECT_TRUE(g[i]._data == i);
	}


}
Ejemplo n.º 3
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;
}
Ejemplo n.º 4
0
int main(int argc, char ** argv)
{
	double nx = 2.0/7.0, ny = 6.0/7.0, nz = 3.0/7.0;
	double px = 0.5, py = 0.5, pz = 0.5;

	if( argc < 2 )
	{
		std::cout << "Usage: " << argv[0] << " mesh [mesh_out=grid.pmf] [nx=0] [ny=0] [nz=1] [px=0.5] [py=0.5] [pz=0.5]" << std::endl;
		return -1;
	}

	std::string grid_out = "grid.pmf";

	if( argc > 2 ) grid_out = std::string(argv[2]);
	if( argc > 3 ) nx = atof(argv[3]);
	if( argc > 4 ) ny = atof(argv[4]);
	if( argc > 5 ) nz = atof(argv[5]);
	if( argc > 6 ) px = atof(argv[6]);
	if( argc > 7 ) py = atof(argv[7]);
	if( argc > 8 ) pz = atof(argv[8]);

	double d = nx*px+ny*py+nz*pz;

	Mesh m;
	m.Load(argv[1]);
	m.SetTopologyCheck(NEED_TEST_CLOSURE|PROHIBIT_MULTILINE|PROHIBIT_MULTIPOLYGON|GRID_CONFORMITY|DEGENERATE_EDGE|DEGENERATE_FACE|DEGENERATE_CELL | FACE_EDGES_ORDER);
	//m.RemTopologyCheck(THROW_EXCEPTION);
	Tag sliced = m.CreateTag("SLICED",DATA_BULK,FACE|EDGE|NODE,FACE|EDGE|NODE,1);

	std::cout << "Cells: " << m.NumberOfCells() << std::endl;
	std::cout << "Faces: " << m.NumberOfFaces() << std::endl;

	MarkerType slice = m.CreateMarker();
	int nslice = 0, nmark = 0;
	for(Mesh::iteratorEdge it = m.BeginEdge(); it != m.EndEdge(); ++it)
	{
		double p[3];
		Storage::real_array c0 = it->getBeg()->Coords();
		Storage::real_array c1 = it->getEnd()->Coords();
		double r0 = c0[0]*nx+c0[1]*ny+c0[2]*nz - d;
		double r1 = c1[0]*nx+c1[1]*ny+c1[2]*nz - d;
		//std::cout << "r0 " << r0 << " r1 " << r1 << std::endl;
		if( r0*r1 < -1.0e-12 )
		{
			p[0] = (r0*c1[0] - r1*c0[0])/(r0-r1);
			p[1] = (r0*c1[1] - r1*c0[1])/(r0-r1);
			p[2] = (r0*c1[2] - r1*c0[2])/(r0-r1);
			//std::cout << "p " << p[0] << " " << p[1] << " " << p[2] << std::endl;
			Node n = m.CreateNode(p);
			n.Bulk(sliced) = 1;
			n.SetMarker(slice);
			bool was_sliced = it->HaveData(sliced) ? true : false;
			ElementArray<Edge> ret = Edge::SplitEdge(it->self(),ElementArray<Node>(&m,1,n.GetHandle()),0);
			if( was_sliced ) for(int q = 0; q < ret.size(); ++q) ret[q]->Bulk(sliced) = 1;
			nslice++;
		}
		else
		{
			if( fabs(r0) < 1.0e-6 )
			{
				it->getBeg()->SetMarker(slice);
				nmark++;
			}
			if( fabs(r1) < 1.0e-6 )
			{
				it->getEnd()->SetMarker(slice);
				nmark++;
			}
		}
	}

	std::cout << "sliced edges: " << nslice << " marked nodes: " << nmark << std::endl;

	if( !Element::CheckConnectivity(&m) )
		std::cout << "Connectivity is broken" << std::endl;
	
	nslice = 0;
	for(Mesh::iteratorFace it = m.BeginFace(); it != m.EndFace(); ++it)
	{
		ElementArray<Node> nodes = it->getNodes(slice); //those nodes should be ordered so that each pair forms an edge
		if( nodes.size() > 1 ) // if there is 1, then only one vertex touches the plane
		{
			//if there is more then two, then original face is non-convex
			if( nodes.size() > 2 ) std::cout << "Looks like face " << it->LocalID() << " is nonconvex" << std::endl;
			else
			{
				Edge e = m.CreateEdge(nodes).first;
				e.Bulk(sliced) = 1;
				e.SetMarker(slice);
				bool was_sliced = it->HaveData(sliced) ? true : false;
				ElementArray<Face> ret = Face::SplitFace(it->self(),ElementArray<Edge>(&m,1,e.GetHandle()),0);
				if( was_sliced ) for(int q = 0; q < ret.size(); ++q) ret[q]->Bulk(sliced) = 1;
				nslice++;
			}
		}
		//else std::cout << "Only one adjacent slice node, face " << it->LocalID() << std::endl;
	}

	nmark = 0;
	for(Mesh::iteratorEdge it = m.BeginEdge(); it != m.EndEdge(); ++it)
		if( !it->GetMarker(slice) && it->getBeg()->GetMarker(slice) && it->getEnd()->GetMarker(slice) )
		{
			it->SetMarker(slice);
			nmark++;
		}

	std::cout << "sliced faces: " << nslice << " marked edges: " << nmark << std::endl;

	if( !Element::CheckConnectivity(&m) )
		std::cout << "Connectivity is broken" << std::endl;
		
	
	nslice = 0;
	MarkerType visited = m.CreateMarker();
	for(Mesh::iteratorCell it = m.BeginCell(); it != m.EndCell(); ++it)
	{
		ElementArray<Edge> edges = it->getEdges(slice);
		if( edges.size() >= 3 ) //these should form a triangle
		{
			//order edges
			ElementArray<Edge> order_edges(&m);
			order_edges.push_back(edges[0]);
			order_edges.SetMarker(visited);
			while(order_edges.size() != edges.size() )
			{
				for(int k = 0; k < edges.size(); ++k) if( !edges[k]->GetMarker(visited) )
				{
					if( edges[k]->getBeg() == order_edges.back()->getBeg() || edges[k]->getBeg() == order_edges.back()->getEnd() ||
						edges[k]->getEnd() == order_edges.back()->getBeg() || edges[k]->getEnd() == order_edges.back()->getEnd() )
					{
						order_edges.push_back(edges[k]);
						order_edges.back().SetMarker(visited);
					}
				}
			}
			edges.RemMarker(visited);
			Face f = m.CreateFace(order_edges).first;
			f.Bulk(sliced) = 1;
			Cell::SplitCell(it->self(),ElementArray<Face>(&m,1,f.GetHandle()),0);
			nslice++;
		}
	}
	m.ReleaseMarker(visited);

	std::cout << "sliced cells: " << nslice << std::endl;
	
	if( !Element::CheckConnectivity(&m) )
		std::cout << "Connectivity is broken" << std::endl;

	Tag material = m.CreateTag("MATERIAL",DATA_INTEGER,CELL,NONE,1);

	for(Mesh::iteratorCell it = m.BeginCell(); it != m.EndCell(); ++it)
	{
		double cnt[3];
		it->Centroid(cnt);
		double v = cnt[0]*nx+cnt[1]*ny+cnt[2]*nz-d;
		if( v < 0.0 )
			it->Integer(material) = 0;
		else
			it->Integer(material) = 1;
	}
	

	m.ReleaseMarker(slice,NODE|EDGE);

	m.Save(grid_out);
	return 0;
}
Ejemplo n.º 5
0
ConvectionDiffusion::ConvectionDiffusion(Mesh * _m, Tag _tag_U, Tag _tag_K, Tag _tag_BC, MarkerType _boundary_face, bool correct_convection, bool correct_diffusion) 
		: m(_m), tag_U(_tag_U), tag_K(_tag_K), tag_BC(_tag_BC), boundary_face(_boundary_face)
{
	perform_correction_diffusion = correct_convection;
	perform_correction_convection = correct_diffusion;
	if( tag_U.isValid() )
	{
		//4 entries - triplet for upwind corrector, including the cell
		//back cell corrector
		tag_CONV_CB = m->CreateTag("CONV_BACK_COEFS"   ,DATA_REAL     ,FACE,NONE,4);
		tag_CONV_EB = m->CreateTag("CONV_BACK_ELEMS"   ,DATA_REFERENCE,FACE,NONE,4);
		tag_CONV_RB = m->CreateTag("CONV_BACK_RHS"     ,DATA_REAL     ,FACE,NONE,1);
		//front cell corrector
		tag_CONV_CF = m->CreateTag("CONV_FRONT_COEFS"  ,DATA_REAL     ,FACE,NONE,4);
		tag_CONV_EF = m->CreateTag("CONV_FRONT_ELEMS"  ,DATA_REFERENCE,FACE,NONE,4);
		tag_CONV_RF = m->CreateTag("CONV_FRONT_RHS"    ,DATA_REAL     ,FACE,NONE,1);
		//upstream
		tag_CONV_CU = m->CreateTag("CONV_UPSTREAM_COEF",DATA_REAL     ,FACE,NONE,1);
		tag_CONV_EU = m->CreateTag("CONV_UPSTREAM_ELEM",DATA_REFERENCE,FACE,NONE,1);
		tag_CONV_RU = m->CreateTag("CONV_UPSTREAM_RHS" ,DATA_REAL     ,FACE,NONE,1);
		tag_CONV_VU = m->CreateTag("CONV_UPSTREAM_CORR",DATA_REAL     ,FACE,NONE,6);
		//flag
		tag_CONV_F = m->CreateTag("CONV_FLAG"          ,DATA_BULK     ,FACE,NONE,1);
	}
	if( tag_K.isValid() )
	{
		//4 entries - triplet for transversal corrector, including the cell
		//back cell corrector
		tag_DIFF_CB = m->CreateTag("DIFF_BACK_COEFS"   ,DATA_REAL     ,FACE,NONE,4);
		tag_DIFF_EB = m->CreateTag("DIFF_BACK_ELEMS"   ,DATA_REFERENCE,FACE,NONE,4);
		tag_DIFF_RB = m->CreateTag("DIFF_BACK_RHS"     ,DATA_REAL     ,FACE,NONE,1);
		//front cell corrector
		tag_DIFF_CF = m->CreateTag("DIFF_FRONT_COEFS"  ,DATA_REAL     ,FACE,NONE,4);
		tag_DIFF_EF = m->CreateTag("DIFF_FRONT_ELEMS"  ,DATA_REFERENCE,FACE,NONE,4);
		tag_DIFF_RF = m->CreateTag("DIFF_FRONT_RHS"    ,DATA_REAL     ,FACE,NONE,1);
		//two-point transmissibility
		tag_DIFF_CT = m->CreateTag("DIFF_TP_COEF"      ,DATA_REAL     ,FACE,NONE,1);
		tag_DIFF_RT = m->CreateTag("DIFF_TP_RHS"       ,DATA_REAL     ,FACE,NONE,1);
		tag_DIFF_VT = m->CreateTag("DIFF_TP_CORR"      ,DATA_REAL     ,FACE,NONE,6);
		//flag
		tag_DIFF_F = m->CreateTag("DIFF_FLAG"          ,DATA_BULK     ,FACE,NONE,1);
	}

	build_flux = 0;
		
	if( m->GetProcessorsNumber() > 1 )
	{
		build_flux = m->CreateMarker();
#if defined(USE_OMP)
#pragma omp for
#endif
		for(integer q = 0; q < m->FaceLastLocalID(); ++q ) if( m->isValidFace(q) )
		{
			Face fKL = m->FaceByLocalID(q);
			Element::Status stat = fKL->BackCell()->GetStatus();
			if( fKL->FrontCell().isValid() ) stat |= fKL->FrontCell()->GetStatus();
			if( stat & (Element::Shared | Element::Owned) )
				fKL->SetMarker(build_flux);
		}	
	}

	initialization_failure = false; //there is a failure during intialization
	//Precompute two-point part, transversal correction direction,
	// upstream and upstream correction directions and flags
#if defined(USE_OMP)
#pragma omp parallel
#endif
	{
		//private memory
		rMatrix	xK(1,3), //center of cell K
				yK(1,3), //projection of xK onto interface
				xL(1,3), //center of cell L
				yL(1,3), //projection of xL onto interface
				xKL(1,3), //center of face common to K and L
				nKL(1,3), //normal vector to face
				KKn(1,3), //co-normal at cell K
				KLn(1,3), //co-normal at cell L
				v(1,3), //vector for correction
				uK(1,3), //vector for upwind correction in back cell
				uL(1,3), //vector for upwind correction in front cell
				r(1,3), //path to reach upstream concentration from downstream concentration
				r0(1,3),
				KK(3,3), //tenosr at cell K
				KL(3,3), //tensor at cell L
				KD(3,3), //difference of tensors
				gammaK(1,3), //transversal part of co-normal at cell K
				gammaL(1,3),  //transversal part of co-normal at cell L
				iT(3,3), //heterogeneous interpolation tensor
				iC(1,3) //heterogeneous interpolation correction
				;
		real	A, //area of the face
				U, //normal component of the velocity
				C, //coefficient for upstream cell
				T, //two-point transmissibility
				R, //right hand side
				dK, //distance from center to interface at cell K
				dL, //distance from center to interface at cell L
				lambdaK, //projection of co-normal onto normal at cell K
				lambdaL //projection of co-normal onto normal at cell L
				;
		const real eps = degenerate_diffusion_regularization;
		Cell cK, cL, cU;
		Face fKL;
		bulk flag_DIFF, flag_CONV;
		KK.Zero();
		KL.Zero();
		KD.Zero();
		U = 0.0;
#if defined(USE_OMP)
#pragma omp for
#endif
		for(integer q = 0; q < m->FaceLastLocalID(); ++q ) if( m->isValidFace(q) )
		{
			fKL = m->FaceByLocalID(q);
			if( !BuildFlux(fKL) ) continue;

			fKL.Centroid(xKL.data());
			fKL.UnitNormal(nKL.data());
			A = fKL.Area();
			if( tag_U.isValid() ) U = fKL.Real(tag_U);
					
			cK = fKL.BackCell();
			cL = fKL.FrontCell();
			assert(cK.isValid());
					
			cK.Centroid(xK.data());
			dK = nKL.DotProduct(xKL-xK);
			yK = xK + dK*nKL;
			if( tag_K.isValid() )
				KK = rMatrix::FromTensor(cK.RealArray(tag_K).data(),cK.RealArray(tag_K).size());//.Transpose();
			KKn = nKL*KK;
			lambdaK = nKL.DotProduct(KKn);
			gammaK = KKn - lambdaK*nKL;
					
			//Diffusion part
			uK.Zero();
			uL.Zero();
			if( cL.isValid() ) //internal, both cells are present
			{
				cL.Centroid(xL.data());
				dL = nKL.DotProduct(xL-xKL);
				yL = xL - dL*nKL;
				if( tag_K.isValid() )
					KL = rMatrix::FromTensor(cL.RealArray(tag_K).data(),cL.RealArray(tag_K).size());//.Transpose();
				KLn = nKL*KL;
				lambdaL = nKL.DotProduct(KLn);
				gammaL = KLn - lambdaL*nKL;
						
						
				//don't forget the area!
				R = 0;
				if( split_diffusion )
				{
					uK = A * (lambdaK*lambdaL*(yK-yL) + lambdaL*dK*gammaK + lambdaK*dL*gammaL)/(dK*lambdaL+dL*lambdaK + 1.0e-100);
					uL = uK;
					T = A * lambdaK*lambdaL/(dK*lambdaL+dL*lambdaK + 1.0e-100);
				}
				else //un-splitted diffusion
				{
					uK = A * KKn;
					uL = A * KLn;
					T = 0;
				}

						
				//internal
				if( uK.FrobeniusNorm() > 0 || uL.FrobeniusNorm() > 0 )
					flag_DIFF = 3;
				else
					flag_DIFF = 2;
			}
			else if( fKL.GetMarker(boundary_face) ) //boundary interface
			{
				//don't forget the area!
				if( split_diffusion )
				{
					uK = KKn - ((xKL - xK) * lambdaK / dK);
					T = lambdaK / dK;
				}
				else //un-splitted diffusion
				{
					uK = KKn;
					T = 0;
				}
						
				real bcconds[3] = {0.0,1.0,0.0}; //pure neumann boundary condition
				if( tag_BC.isValid() && fKL.HaveData(tag_BC) ) //are there boundary conditions on face?
				{
					//retrive boundary conditions
					real_array bc = fKL.RealArray(tag_BC);
					bcconds[0] = bc[0];
					bcconds[1] = bc[1];
					bcconds[2] = bc[2];
				}

				//account for boundary conditions
				R  = A*T*bcconds[2]/(bcconds[0] + bcconds[1]*T + 1.0e-100);
				uK *=A*  bcconds[0]/(bcconds[0] + bcconds[1]*T + 1.0e-100);
				T  *=A*  bcconds[0]/(bcconds[0] + bcconds[1]*T + 1.0e-100);
						
				//on BC
				if( uK.FrobeniusNorm() > 0 )
					flag_DIFF = 1;
				else
					flag_DIFF = 0;
			}
			else std::cout << "No adjacent cell on non-boundary face" << std::endl;
			//record data for diffusion part
			if( tag_K.isValid() )
			{
				fKL.Bulk(tag_DIFF_F) = flag_DIFF;
				fKL.Real(tag_DIFF_RT) = R;
				fKL.Real(tag_DIFF_CT) = T;
				real_array VT = fKL.RealArray(tag_DIFF_VT);
				VT[0] = uK(0,0);
				VT[1] = uK(0,1);
				VT[2] = uK(0,2);
				VT[3] = -uL(0,0);
				VT[4] = -uL(0,1);
				VT[5] = -uL(0,2);
			}
			//Advection part
			uK.Zero();
			uL.Zero();
			C = 0.0;
			cU = InvalidCell();
			R = 0;
			
			if( U > 0.0 ) //flow out of back cell to front cell
			{
				cU = cK;
				C = U*A;
				
				//upstream corrector
				uK = (xK - xKL)*U*A;
						
				//downstream corrector
				if( cL.isValid() ) //internal face
				{
					r0 = r = xK - xL;
					if( tag_K.isValid() ) //heterogeneous media
					{
						KD = KL - KK;
						if( KD.FrobeniusNorm() > 0.0 ) 
						{
							KD /= lambdaK + eps;
							iT = (rMatrix::Unit(3) + nKL.Transpose()*nKL*KD);
							iC = -nKL*dL*KD;
							r = (r*iT - iC)*(lambdaK/(lambdaK+eps)) + r*(eps/(lambdaK+eps));
							//r = (r*iT - iC)*(lambdaK/(lambdaK+eps)) + (r + nKL*(KL-KK)/(U+eps))*(eps/(lambdaK+eps));
						}
					}
					uL = (xKL - xL - r)*U*A;
							
					flag_CONV = 2; //internal
				}
				else if( fKL.GetMarker(boundary_face) ) flag_CONV = 1; //on outlet BC
				else std::cout << "No adjacent cell on non-boundary face" << std::endl;
			}
			else if( U < 0.0 ) //flow out of front cell to back cell
			{
				if( cL.isValid() ) //internal face
				{
					cU = cL;
					C = U*A;
							
					uL = (xKL - xL)*U*A;
							
					r = xL - xK;
					if( tag_K.isValid() ) //heterogeneous media
					{
						KD = KK - KL;
						if( KD.FrobeniusNorm() > 0.0 ) 
						{
							KD /= lambdaL + eps;
							iT = (rMatrix::Unit(3) + nKL.Transpose()*nKL*KD);
							iC = nKL*dK*KD;
							r = (r*iT - iC)*(lambdaL/(lambdaL+eps)) + r*(eps/(lambdaL+eps));
							//r = (r*iT - iC)*(lambdaL/(lambdaL+eps)) + (r + nKL*(KK-KL)/(U-eps))*(eps/(lambdaL+eps));
						}
					}
					uK = (r + xK - xKL)*U*A;
							
					flag_CONV = 2; //internal
				}
				else if( fKL.GetMarker(boundary_face) )//boundary face
				{
					real bcconds[3] = {0.0,1.0,0.0}; //pure neumann boundary condition
					if( tag_BC.isValid() && fKL.HaveData(tag_BC) ) //are there boundary conditions on face?
					{
						//retrive boundary conditions
						real_array bc = fKL.RealArray(tag_BC);
						bcconds[0] = bc[0];
						bcconds[1] = bc[1];
						bcconds[2] = bc[2];
					}
					if( bcconds[0] > 0 && fabs(bcconds[1]) < 1.0e-7 ) //Dirichlet BC
					{
						C = 0;
						R = U*A*bcconds[2]/bcconds[0];
								
						flag_CONV = 0; //on inlet BC
					}
					else if( tag_K.isValid() ) //get expression out of diffusion
					{
						v = - A * (KKn - (xKL - xK) * lambdaK / dK);
						T =   A * lambdaK / dK;
								
						cU = cK;
						C = U*A*T*bcconds[1]/(bcconds[0] + bcconds[1]*T + 1.0e-100);
						R = U*A  *bcconds[2]/(bcconds[0] + bcconds[1]*T + 1.0e-100);
						uK =U*A*v*bcconds[1]/(bcconds[0] + bcconds[1]*T + 1.0e-100);
								
						flag_CONV = 1; //treat as outlet BC
					}
					else
					{
						if( bcconds[0] > 0 && bcconds[1] > 0 ) //Mixed BC
						{
							initialization_failure = true;
							std::cout << "Mixed BC type on inlet boundary face " << fKL->LocalID() << " is inconsistent for pure advection" << std::endl;
						}
						else  if( bcconds[1] > 0 ) // Neumann BC
						{
							initialization_failure = true;
							std::cout << "Neumann BC type on inlet boundary face " << fKL->LocalID() << " is inconsistent for pure advection" << std::endl;
						}
					}
				}
				else std::cout << "No adjacent cell on non-boundary face" << std::endl;
			}
			else flag_CONV = 0; //otherwise velocity is zero, no flow through face
			//record data for advection part
			if( tag_U.isValid() )
			{
				fKL.Bulk(tag_CONV_F) = flag_CONV;
				fKL.Real(tag_CONV_CU) = C;
				fKL.Reference(tag_CONV_EU) = cU.GetHandle();
				fKL.Real(tag_CONV_RU) = R;
				real_array VU = fKL.RealArray(tag_CONV_VU);
				VU[0] = uK(0,0);
				VU[1] = uK(0,1);
				VU[2] = uK(0,2);
				VU[3] = uL(0,0);
				VU[4] = uL(0,1);
				VU[5] = uL(0,2);
			} // tag_U is defined
		} // for q
	} //openmp
	Tag failure = m->CreateTag("FAILURE",DATA_INTEGER,CELL,NONE,1);
	//Compute triplets
	integer negative = 0, total = 0;
#if defined(USE_OMP)
#pragma omp parallel reduction(+:negative,total)
#endif
	{
		Cell cK; //current cell
		Face fKL;
		ElementArray<Face> faces; //faces of the cell
		std::vector<Stencil> compute; //approximations to be computed
		Tag tag_iC, tag_iT; //temporary data used for interpolation tensors
		{
			std::stringstream name;
			name << "INTERPOLATION_TENSOR_" << m->GetLocalProcessorRank();
			tag_iT = m->CreateTag(name.str(),DATA_REAL,CELL,NONE);
			name.clear();
			name << "INTERPOLATION_CORRECTION_" << m->GetLocalProcessorRank();
			tag_iC = m->CreateTag(name.str(),DATA_REAL,CELL,NONE);
		}
		bulk flag;
		real_array v;
#if defined(USE_OMP)
#pragma omp for 
#endif
		for(integer q = 0; q < m->CellLastLocalID(); ++q ) if( m->isValidCell(q) )
		{
			cK = m->CellByLocalID(q);
			compute.clear();
			faces = cK.getFaces();
			for(integer k = 0; k < faces.size(); ++k)
			{
				fKL = faces[k];

				if( !BuildFlux(fKL) ) continue;
				//Diffusion stencils
				if( tag_K.isValid() )
				{
					flag = fKL.Bulk(tag_DIFF_F);
					if( flag == 3 || flag == 1 )
					{
						Stencil s;
						s.type = DIFFUSION;
						if( fKL.FaceOrientedOutside(cK) )
						{
							s.coefs = fKL.RealArray(tag_DIFF_CB);
							s.elems = fKL.ReferenceArray(tag_DIFF_EB);
							s.rhs = &fKL.Real(tag_DIFF_RB);
							v = fKL.RealArray(tag_DIFF_VT);
							s.v[0] = v[0];
							s.v[1] = v[1];
							s.v[2] = v[2];
							s.sign = 1;
						}
						else
						{
							s.coefs = fKL.RealArray(tag_DIFF_CF);
							s.elems = fKL.ReferenceArray(tag_DIFF_EF);
							s.rhs = &fKL.Real(tag_DIFF_RF);
							v = fKL.RealArray(tag_DIFF_VT);
							s.v[0] = v[3];
							s.v[1] = v[4];
							s.v[2] = v[5];
							s.sign = -1;
						}
						if( s.v[0]*s.v[0] + s.v[1]*s.v[1] + s.v[2]*s.v[2] > 0.0 )
							compute.push_back(s);
					}
				}
				//Advection stencils
				if( tag_U.isValid() )
				{
					flag = fKL.Bulk(tag_CONV_F);
					if( flag >= 2 || flag == 1 )
					{
						Stencil s;
						s.type = CONVECTION;
						if( fKL.FaceOrientedOutside(cK) )
						{
							s.coefs = fKL.RealArray(tag_CONV_CB);
							s.elems = fKL.ReferenceArray(tag_CONV_EB);
							s.rhs = &fKL.Real(tag_CONV_RB);
							v = fKL.RealArray(tag_CONV_VU);
							s.v[0] = v[0];
							s.v[1] = v[1];
							s.v[2] = v[2];
							s.sign = -1;
						}
						else
						{
							s.coefs = fKL.RealArray(tag_CONV_CF);
							s.elems = fKL.ReferenceArray(tag_CONV_EF);
							s.rhs = &fKL.Real(tag_CONV_RF);
							v = fKL.RealArray(tag_CONV_VU);
							s.v[0] = v[3];
							s.v[1] = v[4];
							s.v[2] = v[5];
							s.sign = 1;
						}
						if( s.v[0]*s.v[0] + s.v[1]*s.v[1] + s.v[2]*s.v[2] > 0.0 )
							compute.push_back(s);
					}
				}
			}
			//Gathered all the stencils at once
			if( !compute.empty() )
			{
				if( !find_stencils(cK,compute,tag_BC,tag_K,tag_iT,tag_iC,boundary_face,bridge_layers,degenerate_diffusion_regularization,max_layers) )
				{
					initialization_failure = true;
					cK.Integer(failure) = 1;
					std::cout << "Cannot find stencil for cell " << cK->LocalID() << std::endl;
					for(size_t it = 0; it < compute.size(); ++it)
					{
						if( !compute[it].computed )
						{
							std::cout << (compute[it].type == DIFFUSION ? "Diffusion" : "Advection");
							std::cout << " vec (" << compute[it].v[0] << "," << compute[it].v[1] << "," << compute[it].v[2] << ")";
							std::cout << std::endl;
						}
					}
					std::cout << "Total: " << compute.size() << std::endl;
					find_stencils(cK,compute,tag_BC,tag_K,tag_iT,tag_iC,boundary_face,bridge_layers,degenerate_diffusion_regularization,max_layers);
				}
				else for(size_t it = 0; it < compute.size(); ++it)
					if( !compute[it].nonnegative ) negative++;
				total += (integer)compute.size();
			}
		} //end of loop over cells
		//release interpolation tags
		m->DeleteTag(tag_iC);
		m->DeleteTag(tag_iT);
	} //openmp

	negative = m->Integrate(negative);
	total = m->Integrate(total);
	if( m->GetProcessorRank() == 0 )
			std::cout << " negative flux approximation: " << negative << "/" << total << std::endl;

	{ //Synchronize initialization_failure
		integer sync = (initialization_failure ? 1 : 0);
		sync = m->Integrate(sync);
		if( sync ) initialization_failure = true;
	}
	if( !initialization_failure )
		m->DeleteTag(failure);
}