<commit_before>/*
 * Copyright 2014 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "GrGLShaderStringBuilder.h"
#include "GrSKSLPrettyPrint.h"
#include "SkAutoMalloc.h"
#include "SkSLCompiler.h"
#include "SkSLGLSLCodeGenerator.h"
#include "SkTraceEvent.h"
#include "gl/GrGLGpu.h"
#include "ir/SkSLProgram.h"

#define GL_CALL(X) GR_GL_CALL(gpu->glInterface(), X)
#define GL_CALL_RET(R, X) GR_GL_CALL_RET(gpu->glInterface(), R, X)

// Print the source code for all shaders generated.
static const bool c_PrintShaders{false};

static SkString list_source_with_line_numbers(const char* source) {
    SkTArray<SkString> lines;
    SkStrSplit(source, "\n", kStrict_SkStrSplitMode, &lines);
    SkString result;
    for (int line = 0; line < lines.count(); ++line) {
        // Print the shader one line at the time so it doesn't get truncated by the adb log.
        result.appendf("%4i\t%s\n", line + 1, lines[line].c_str());
    }
    return result;
}

SkString list_shaders(const char** skslStrings, int* lengths, int count, const SkSL::String& glsl) {
    SkString sksl = GrSKSLPrettyPrint::PrettyPrint(skslStrings, lengths, count, false);
    SkString result("SKSL:\n");
    result.append(list_source_with_line_numbers(sksl.c_str()));
    if (!glsl.isEmpty()) {
        result.append("GLSL:\n");
        result.append(list_source_with_line_numbers(glsl.c_str()));
    }
    return result;
}

std::unique_ptr<SkSL::Program> translate_to_glsl(const GrGLContext& context, GrGLenum type,
                                                 const char** skslStrings, int* lengths, int count,
                                                 const SkSL::Program::Settings& settings,
                                                 SkSL::String* glsl) {
    SkString sksl;
#ifdef SK_DEBUG
    sksl = GrSKSLPrettyPrint::PrettyPrint(skslStrings, lengths, count, false);
#else
    for (int i = 0; i < count; i++) {
        sksl.append(skslStrings[i], lengths[i]);
    }
#endif
    SkSL::Compiler* compiler = context.compiler();
    std::unique_ptr<SkSL::Program> program;
    SkSL::Program::Kind programKind;
    switch (type) {
        case GR_GL_VERTEX_SHADER:   programKind = SkSL::Program::kVertex_Kind;   break;
        case GR_GL_FRAGMENT_SHADER: programKind = SkSL::Program::kFragment_Kind; break;
        case GR_GL_GEOMETRY_SHADER: programKind = SkSL::Program::kGeometry_Kind; break;
    }
    program = compiler->convertProgram(programKind, sksl, settings);
    if (!program || !compiler->toGLSL(*program, glsl)) {
        SkDebugf("SKSL compilation error\n----------------------\n");
        SkDebugf(list_shaders(skslStrings, lengths, count, *glsl).c_str());
        SkDebugf("\nErrors:\n%s\n", compiler->errorText().c_str());
        SkDEBUGFAIL("SKSL compilation failed!\n");
        return nullptr;
    }
    return program;
}

GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx,
                                    GrGLuint programId,
                                    GrGLenum type,
                                    const char** skslStrings,
                                    int* lengths,
                                    int count,
                                    GrGpu::Stats* stats,
                                    const SkSL::Program::Settings& settings,
                                    SkSL::Program::Inputs* outInputs) {
    const GrGLInterface* gli = glCtx.interface();

    SkSL::String glsl;
    auto program = translate_to_glsl(glCtx, type, skslStrings, lengths, count, settings, &glsl);
    if (!program) {
        return 0;
    }

    // Specify GLSL source to the driver.
    GrGLuint shaderId;
    GR_GL_CALL_RET(gli, shaderId, CreateShader(type));
    if (0 == shaderId) {
        return 0;
    }
    const char* glslChars = glsl.c_str();
    GrGLint glslLength = (GrGLint) glsl.size();
    GR_GL_CALL(gli, ShaderSource(shaderId, 1, &glslChars, &glslLength));

    // Lazy initialized pretty-printed shaders for dumping.
    SkString shaderDebugString;

    // Trace event for shader preceding driver compilation
    bool traceShader;
    TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("skia.gpu"), &traceShader);
    if (traceShader) {
        if (shaderDebugString.isEmpty()) {
            shaderDebugString = list_shaders(skslStrings, lengths, count, glsl);
        }
        TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("skia.gpu"), "skia_gpu::GLShader",
                             TRACE_EVENT_SCOPE_THREAD, "shader",
                             TRACE_STR_COPY(shaderDebugString.c_str()));
    }

    stats->incShaderCompilations();
    GR_GL_CALL(gli, CompileShader(shaderId));

    // Calling GetShaderiv in Chromium is quite expensive. Assume success in release builds.
    bool checkCompiled = kChromium_GrGLDriver != glCtx.driver();
#ifdef SK_DEBUG
    checkCompiled = true;
#endif
    if (checkCompiled) {
        GrGLint compiled = GR_GL_INIT_ZERO;
        GR_GL_CALL(gli, GetShaderiv(shaderId, GR_GL_COMPILE_STATUS, &compiled));

        if (!compiled) {
            if (shaderDebugString.isEmpty()) {
                shaderDebugString = list_shaders(skslStrings, lengths, count, glsl);
            }
            SkDebugf("GLSL compilation error\n----------------------\n");
            SkDebugf(shaderDebugString.c_str());
            GrGLint infoLen = GR_GL_INIT_ZERO;
            GR_GL_CALL(gli, GetShaderiv(shaderId, GR_GL_INFO_LOG_LENGTH, &infoLen));
            SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
            if (infoLen > 0) {
                // retrieve length even though we don't need it to workaround bug in Chromium cmd
                // buffer param validation.
                GrGLsizei length = GR_GL_INIT_ZERO;
                GR_GL_CALL(gli, GetShaderInfoLog(shaderId, infoLen+1, &length, (char*)log.get()));
                SkDebugf("Errors:\n%s\n", (const char*) log.get());
            }
            SkDEBUGFAIL("GLSL compilation failed!");
            GR_GL_CALL(gli, DeleteShader(shaderId));
            return 0;
        }
    }

    if (c_PrintShaders) {
        const char* typeName = "Unknown";
        switch (type) {
            case GR_GL_VERTEX_SHADER: typeName = "Vertex"; break;
            case GR_GL_GEOMETRY_SHADER: typeName = "Geometry"; break;
            case GR_GL_FRAGMENT_SHADER: typeName = "Fragment"; break;
        }
        SkDebugf("---- %s shader ----------------------------------------------------\n", typeName);
        if (shaderDebugString.isEmpty()) {
            shaderDebugString = list_shaders(skslStrings, lengths, count, glsl);
        }
        SkDebugf(shaderDebugString.c_str());
    }

    // Attach the shader, but defer deletion until after we have linked the program.
    // This works around a bug in the Android emulator's GLES2 wrapper which
    // will immediately delete the shader object and free its memory even though it's
    // attached to a program, which then causes glLinkProgram to fail.
    GR_GL_CALL(gli, AttachShader(programId, shaderId));
    *outInputs = program->fInputs;
    return shaderId;
}

void GrGLPrintShader(const GrGLContext& context, GrGLenum type, const char** skslStrings,
                     int* lengths, int count, const SkSL::Program::Settings& settings) {
    SkSL::String glsl;
    if (translate_to_glsl(context, type, skslStrings, lengths, count, settings, &glsl)) {
        SkDebugf(list_shaders(skslStrings, lengths, count, glsl).c_str());
    }
}
<commit_msg>gl: print shader sources one line at a time<commit_after>/*
 * Copyright 2014 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "GrGLShaderStringBuilder.h"
#include "GrSKSLPrettyPrint.h"
#include "SkAutoMalloc.h"
#include "SkSLCompiler.h"
#include "SkSLGLSLCodeGenerator.h"
#include "SkTraceEvent.h"
#include "gl/GrGLGpu.h"
#include "ir/SkSLProgram.h"

#define GL_CALL(X) GR_GL_CALL(gpu->glInterface(), X)
#define GL_CALL_RET(R, X) GR_GL_CALL_RET(gpu->glInterface(), R, X)

// Print the source code for all shaders generated.
static const bool c_PrintShaders{false};

static void print_source_lines_with_numbers(const char* source,
                                            std::function<void(const char*)> println) {
    SkTArray<SkString> lines;
    SkStrSplit(source, "\n", kStrict_SkStrSplitMode, &lines);
    for (int i = 0; i < lines.count(); ++i) {
        SkString& line = lines[i];
        line.prependf("%4i\t", i + 1);
        println(line.c_str());
    }
}

// Prints shaders one line at the time. This ensures they don't get truncated by the adb log.
static void print_shaders_line_by_line(const char** skslStrings, int* lengths,
                                     int count, const SkSL::String& glsl,
                                     std::function<void(const char*)> println = [](const char* ln) {
                                         SkDebugf("%s\n", ln);
                                     }) {
    SkString sksl = GrSKSLPrettyPrint::PrettyPrint(skslStrings, lengths, count, false);
    println("SKSL:");
    print_source_lines_with_numbers(sksl.c_str(), println);
    if (!glsl.isEmpty()) {
        println("GLSL:");
        print_source_lines_with_numbers(glsl.c_str(), println);
    }
}

std::unique_ptr<SkSL::Program> translate_to_glsl(const GrGLContext& context, GrGLenum type,
                                                 const char** skslStrings, int* lengths, int count,
                                                 const SkSL::Program::Settings& settings,
                                                 SkSL::String* glsl) {
    SkString sksl;
#ifdef SK_DEBUG
    sksl = GrSKSLPrettyPrint::PrettyPrint(skslStrings, lengths, count, false);
#else
    for (int i = 0; i < count; i++) {
        sksl.append(skslStrings[i], lengths[i]);
    }
#endif
    SkSL::Compiler* compiler = context.compiler();
    std::unique_ptr<SkSL::Program> program;
    SkSL::Program::Kind programKind;
    switch (type) {
        case GR_GL_VERTEX_SHADER:   programKind = SkSL::Program::kVertex_Kind;   break;
        case GR_GL_FRAGMENT_SHADER: programKind = SkSL::Program::kFragment_Kind; break;
        case GR_GL_GEOMETRY_SHADER: programKind = SkSL::Program::kGeometry_Kind; break;
    }
    program = compiler->convertProgram(programKind, sksl, settings);
    if (!program || !compiler->toGLSL(*program, glsl)) {
        SkDebugf("SKSL compilation error\n----------------------\n");
        print_shaders_line_by_line(skslStrings, lengths, count, *glsl);
        SkDebugf("\nErrors:\n%s\n", compiler->errorText().c_str());
        SkDEBUGFAIL("SKSL compilation failed!\n");
        return nullptr;
    }
    return program;
}

GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx,
                                    GrGLuint programId,
                                    GrGLenum type,
                                    const char** skslStrings,
                                    int* lengths,
                                    int count,
                                    GrGpu::Stats* stats,
                                    const SkSL::Program::Settings& settings,
                                    SkSL::Program::Inputs* outInputs) {
    const GrGLInterface* gli = glCtx.interface();

    SkSL::String glsl;
    auto program = translate_to_glsl(glCtx, type, skslStrings, lengths, count, settings, &glsl);
    if (!program) {
        return 0;
    }

    // Specify GLSL source to the driver.
    GrGLuint shaderId;
    GR_GL_CALL_RET(gli, shaderId, CreateShader(type));
    if (0 == shaderId) {
        return 0;
    }
    const char* glslChars = glsl.c_str();
    GrGLint glslLength = (GrGLint) glsl.size();
    GR_GL_CALL(gli, ShaderSource(shaderId, 1, &glslChars, &glslLength));

    // Trace event for shader preceding driver compilation
    bool traceShader;
    TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("skia.gpu"), &traceShader);
    if (traceShader) {
        SkString shaderDebugString;
        print_shaders_line_by_line(skslStrings, lengths, count, glsl, [&](const char* ln) {
            shaderDebugString.append(ln);
            shaderDebugString.append("\n");
        });
        TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("skia.gpu"), "skia_gpu::GLShader",
                             TRACE_EVENT_SCOPE_THREAD, "shader",
                             TRACE_STR_COPY(shaderDebugString.c_str()));
    }

    stats->incShaderCompilations();
    GR_GL_CALL(gli, CompileShader(shaderId));

    // Calling GetShaderiv in Chromium is quite expensive. Assume success in release builds.
    bool checkCompiled = kChromium_GrGLDriver != glCtx.driver();
#ifdef SK_DEBUG
    checkCompiled = true;
#endif
    if (checkCompiled) {
        GrGLint compiled = GR_GL_INIT_ZERO;
        GR_GL_CALL(gli, GetShaderiv(shaderId, GR_GL_COMPILE_STATUS, &compiled));

        if (!compiled) {
            SkDebugf("GLSL compilation error\n----------------------\n");
            print_shaders_line_by_line(skslStrings, lengths, count, glsl);
            GrGLint infoLen = GR_GL_INIT_ZERO;
            GR_GL_CALL(gli, GetShaderiv(shaderId, GR_GL_INFO_LOG_LENGTH, &infoLen));
            SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
            if (infoLen > 0) {
                // retrieve length even though we don't need it to workaround bug in Chromium cmd
                // buffer param validation.
                GrGLsizei length = GR_GL_INIT_ZERO;
                GR_GL_CALL(gli, GetShaderInfoLog(shaderId, infoLen+1, &length, (char*)log.get()));
                SkDebugf("Errors:\n%s\n", (const char*) log.get());
            }
            SkDEBUGFAIL("GLSL compilation failed!");
            GR_GL_CALL(gli, DeleteShader(shaderId));
            return 0;
        }
    }

    if (c_PrintShaders) {
        const char* typeName = "Unknown";
        switch (type) {
            case GR_GL_VERTEX_SHADER: typeName = "Vertex"; break;
            case GR_GL_GEOMETRY_SHADER: typeName = "Geometry"; break;
            case GR_GL_FRAGMENT_SHADER: typeName = "Fragment"; break;
        }
        SkDebugf("---- %s shader ----------------------------------------------------\n", typeName);
        print_shaders_line_by_line(skslStrings, lengths, count, glsl);
    }

    // Attach the shader, but defer deletion until after we have linked the program.
    // This works around a bug in the Android emulator's GLES2 wrapper which
    // will immediately delete the shader object and free its memory even though it's
    // attached to a program, which then causes glLinkProgram to fail.
    GR_GL_CALL(gli, AttachShader(programId, shaderId));
    *outInputs = program->fInputs;
    return shaderId;
}

void GrGLPrintShader(const GrGLContext& context, GrGLenum type, const char** skslStrings,
                     int* lengths, int count, const SkSL::Program::Settings& settings) {
    SkSL::String glsl;
    if (translate_to_glsl(context, type, skslStrings, lengths, count, settings, &glsl)) {
        print_shaders_line_by_line(skslStrings, lengths, count, glsl);
    }
}
<|endoftext|>


<commit_before>#ifndef SIMULATE_ENGINE_BASE_HPP_
#define SIMULATE_ENGINE_BASE_HPP_

#include "clotho/powerset/variable_subset.hpp"
#include "clotho/utility/random_generator.hpp"

#include "clotho/classifiers/region_classifier.hpp"

#include <vector>
#include <utility>

template < class URNG, class AlleleType, class LogType, class TimerType >
class simulate_engine_base {
public:
    typedef URNG                                                        rng_type;
    typedef AlleleType                                                  allele_type;
    typedef LogType                                                     log_type;
    typedef TimerType                                                   timer_type;

    typedef unsigned long                                               block_type;

    typedef clotho::utility::random_generator< rng_type, allele_type >  allele_generator;

    typedef clotho::powersets::variable_subset< allele_type, block_type > sequence_type;
    typedef typename sequence_type::pointer                                  sequence_pointer;
    typedef typename sequence_type::powerset_type                            allele_set_type;

    typedef clotho::classifiers::region_classifier< allele_type >            classifier_type;
    typedef clotho::utility::random_generator< rng_type, classifier_type >   classifier_generator;

    typedef std::pair< sequence_pointer, sequence_pointer >                  individual_type;
    typedef std::vector< individual_type >                                   population_type;
    typedef typename population_type::iterator                               population_iterator;
};

#endif  // SIMULATE_ENGINE_BASE_HPP_
<commit_msg>Added compilation specific dependencies for specific types<commit_after>#ifndef SIMULATE_ENGINE_BASE_HPP_
#define SIMULATE_ENGINE_BASE_HPP_

#include "qtl_config.hpp"

#include <vector>
#include <utility>

template < class URNG, class AlleleType, class LogType, class TimerType >
class simulate_engine_base {
public:
    typedef URNG                                                        rng_type;
    typedef AlleleType                                                  allele_type;
    typedef LogType                                                     log_type;
    typedef TimerType                                                   timer_type;

    typedef BLOCK_UNIT_TYPE                                             block_type;

    typedef clotho::utility::random_generator< rng_type, allele_type >  allele_generator;

    typedef SUBSETTYPE< allele_type, block_type >   sequence_type;
    typedef typename sequence_type::pointer         sequence_pointer;
    typedef typename sequence_type::powerset_type   allele_set_type;

    typedef RECOMBTYPE                              classifier_type;
    typedef clotho::utility::random_generator< rng_type, classifier_type >  classifier_generator;

    typedef std::pair< sequence_pointer, sequence_pointer >                  individual_type;
    typedef std::vector< individual_type >                                   population_type;
    typedef typename population_type::iterator                               population_iterator;
};

#endif  // SIMULATE_ENGINE_BASE_HPP_
<|endoftext|>


<commit_before>#include "streamline.h"
#include "inc_glut.h"
#include "color.h"
#include "svg_line.h"

namespace INMOST
{

	void GetVelocity(Element c, const Tag & velocity_tag, ElementType vel_adj, coord pnt, coord & ret)
	{
		coord cnt;
		const Storage::real eps = 1.0e-8;
		Storage::real dist = 0;
		ret[0] = ret[1] = ret[2] = 0;
		c->Centroid(cnt.data());
		if ((cnt - pnt).length() < 1.0e-5)
		{
			ret = coord(c->RealArray(velocity_tag).data());
		}
		else //inverse distance algorithm (consider wlsqr with linear basis)
		{
			ElementArray<Element> adj = c->BridgeAdjacencies(vel_adj == NODE ? CELL : NODE,vel_adj);
			adj.push_back(c);
			for (ElementArray<Element>::iterator it = adj.begin(); it != adj.end(); ++it)
			{
				it->Centroid(cnt.data());
				coord vel = coord(it->RealArray(velocity_tag).data());
				Storage::real l = (cnt - pnt).length() + eps;
				Storage::real omega = 1.0 / (l*l);
				ret += vel*omega;
				dist += omega;
			}
			ret /= dist;
		}
	}

	Storage::real GetSize(Cell c)
	{
		Storage::real bounds[3][2] = { { 1.0e20, -1.0e20 }, { 1.0e20, -1.0e20 }, { 1.0e20, -1.0e20 } };
		ElementArray<Node> nodes = c->getNodes();
		for (ElementArray<Node>::iterator n = nodes.begin(); n != nodes.end(); ++n)
		{
			Storage::real_array cnt = n->Coords();
			for (int k = 0; k < 3; ++k)
			{
				if (bounds[k][0] > cnt[k]) bounds[k][0] = cnt[k];
				if (bounds[k][1] < cnt[k]) bounds[k][1] = cnt[k];
			}
		}
		Storage::real ret = 1.0e+20;
		for (int k = 0; k < 3; ++k) if (bounds[k][1] - bounds[k][0])
			ret = std::min(ret, bounds[k][1] - bounds[k][0]);
		if (ret > 1.0e+19) std::cout << __FILE__ << ":" << __LINE__ << " oops" << std::endl;
		return ret;
	}

	Storage::real GetSize(Element n, const Tag & size_tag)
	{
		ElementArray<Cell> cells = n->getCells();
		Storage::real minsize = 1.0e+20, size;
		for (ElementArray<Cell>::iterator c = cells.begin(); c != cells.end(); ++c)
		{
			size = c->RealDF(size_tag);
			if (minsize > size) minsize = size;
		}
		if (minsize > 1.0e+19) std::cout << __FILE__ << ":" << __LINE__ << " oops" << std::endl;
		return minsize;
	}

	void BuildStreamlines(Mesh *mesh, Tag vel, ElementType vel_def, std::vector<Streamline> & output)
	{
		if (!vel.isDefined(vel_def))
		{
			std::cout << __FILE__ << ":" << __LINE__ << " Velocity was not defined on " << ElementTypeName(vel_def) << std::endl;
			return;
		}
		if (vel.GetDataType() != DATA_REAL)
		{
			std::cout << __FILE__ << ":" << __LINE__ << " Data type for velocity is not floating point" << std::endl;
			return;
		}
		if (vel.GetSize() != 3)
		{
			std::cout << __FILE__ << ":" << __LINE__ << " Expected 3 entries in velocity field for streamlines" << std::endl;
			return;
		}
		printf("preparing octree around mesh, was sets %d\n", mesh->NumberOfSets());
		Octree octsearch = Octree(mesh->CreateSet("octsearch").first);
		octsearch.Construct(vel_def, false); //auto-detect octree or quadtree
		printf("done, sets %d\n", mesh->NumberOfSets());
		printf("building streamlines\n");
		Tag cell_size = mesh->CreateTag("STREAMLINES_TEMPORARY_CELL_SIZES", DATA_REAL, CELL, NONE, 1);
		Storage::real velmax = 0, velmin = 1.0e20, l;
		for (Mesh::iteratorCell c = mesh->BeginCell(); c != mesh->EndCell(); ++c)
		{
			coord velv(c->RealArray(vel).data());
			l = velv.length();
			if (l > velmax) velmax = l;
			if (l < velmin) velmin = l;
			c->RealDF(cell_size) = GetSize(c->self());
		}
		velmax = log(velmax + 1.0e-25);
		velmin = log(velmin + 1.0e-25);

		{
			MarkerType visited = mesh->CreateMarker();

			printf("started building streamlines from boundary elements\n");
			int tot = 0;
			for (Mesh::iteratorElement f = mesh->BeginElement(vel_def); f != mesh->EndElement(); ++f) if (f->Boundary())
				tot++;

			printf("total elements: %d\n",tot);
			int k = 0;
			for (Mesh::iteratorElement f = mesh->BeginElement(vel_def); f != mesh->EndElement(); ++f) if (f->Boundary())
			{
				coord v(f->RealArray(vel).data());
				if (v.length() > 1.0e-4)
				{
					coord nrm(0,0,0);
					if( f->GetElementType() == FACE )
						f->getAsFace().UnitNormal(nrm.data());
					else
					{
						coord ncur;
						int nn = 0;
						ElementArray<Face> faces = f->getFaces();
						for (ElementArray<Face>::iterator ff = faces.begin(); ff != faces.end(); ++ff) if (ff->Boundary())
						{
							ff->UnitNormal(ncur.data());
							nrm+=ncur;
							nn++;
						}
						if( nn )
							nrm /= (double)nn;
						else
							std::cout << __FILE__ << ":" << __LINE__ << " No boundary faces around boundary element" << std::endl;
					}
					double dir = nrm^v;
					if( dir > 0.0 ) //velocity points out of mesh
						dir = -1;
					else dir = 1; //velocity points into mesh
					coord cntf;
					f->Centroid(cntf.data());
					output.push_back(Streamline(octsearch, cntf, vel, vel_def, cell_size, velmin, velmax, dir, visited));

					ElementArray<Edge> edges = f->getEdges();
					for (ElementArray<Edge>::iterator n = edges.begin(); n != edges.end(); ++n)
					{
						coord cntn;
						n->Centroid(cntn.data());
						if (cntn[2] == cntf[2])
						{
							const Storage::real coef[4] = { 0.4, 0.8 };
							for (int q = 0; q < 2; ++q)
								output.push_back(Streamline(octsearch, cntf*coef[q] + cntn*(1 - coef[q]), vel, vel_def, cell_size, velmin, velmax, 1.0, visited));
						}
					}
				}
				k++;
				if (k % 100 == 0)
				{
					printf("%5.2f%%\r", (double)k / (double)tot*100.0);
					fflush(stdout);
				}
			}

			printf("done from boundary faces, total streamlines = %lu\n", output.size());

			printf("started building streamlines from unvisited cells\n");
			tot = 0;
			for (Mesh::iteratorCell it = mesh->BeginCell(); it != mesh->EndCell(); ++it)
				if (!it->GetMarker(visited)) tot++;

			printf("total elements: %d\n", tot);
			k = 0;
			for (Mesh::iteratorCell it = mesh->BeginCell(); it != mesh->EndCell(); ++it)
			{
				if (!it->GetMarker(visited))
				{
					coord cntc;
					it->Centroid(cntc.data());
					if (coord(it->RealArray(vel).data()).length() > 1.0e-4)
					{
						output.push_back(Streamline(octsearch, cntc, vel, vel_def, cell_size, velmin, velmax, 1.0, 0));
						output.push_back(Streamline(octsearch, cntc, vel, vel_def, cell_size, velmin, velmax, -1.0, 0));
					}
				}
				k++;
				if (k % 100 == 0)
				{
					printf("%5.2f%%\r", (double)k / (double)tot*100.0);
					fflush(stdout);
				}
			}
			printf("done from unvisited cells, total streamlines = %lu\n", output.size());

			mesh->ReleaseMarker(visited,vel_def);

		}
		mesh->DeleteTag(cell_size);
		printf("done, total streamlines = %lu\n", output.size());
		printf("killing octree, was sets %d\n", mesh->NumberOfSets());
		octsearch.Destroy();
		printf("done, sets %d\n", mesh->NumberOfSets());

	}

	Streamline::Streamline(const Octree & octsearch, coord pos, Tag velocity_tag, ElementType velocity_defined, Tag cell_size, Storage::real velocity_min, Storage::real velocity_max, Storage::real sign, MarkerType visited)
	{
		Storage::real coef, len, size;
		coord next = pos, vel;
		Element c;
		const int maxsteps = 250;
		points.reserve(maxsteps / 2);
		velarr.reserve(maxsteps / 2);
		points.push_back(pos);
		velarr.push_back(0);
		while (points.size() < maxsteps)
		{
			c = octsearch.FindClosestCell(next.data());
			if (!c.isValid()) break;
			//check we are inside mesh
			/*
			ElementArray<Cell> cells = c->BridgeAdjacencies2Cell(NODE);
			bool inside = false;
			for (ElementArray<Cell>::iterator it = cells.begin(); it != cells.end() && !inside; ++it)
				if( it->Inside(next.data()) ) inside = true;
			if( !inside ) break;
			*/
			c.SetMarker(visited);
			GetVelocity(c, velocity_tag, velocity_defined, next, vel);
			len = vel.length();
			if (len < 1.0e-4) break;
			size = GetSize(c, cell_size);// c->RealDF(cell_size);
			coef = 0.05*size / len;
			next += vel*coef*sign;
			points.push_back(next);
			velarr.push_back((log(len + 1.0e-25) - velocity_min) / (velocity_max - velocity_min));
		}
		//printf("%ld %ld\n",points.size(),velarr.size());
	}

	GLUquadric * cylqs = NULL;
	void drawcylinder(coord a, coord b, double width)
	{
		double matrix[16];
		if (cylqs == NULL)
		{
			cylqs = gluNewQuadric();
			gluQuadricNormals(cylqs, GLU_SMOOTH);
			gluQuadricOrientation(cylqs, GLU_OUTSIDE);
			gluQuadricDrawStyle(cylqs, GLU_FILL);//GLU_SILHOUETTE
		}
		glPushMatrix();
		glTranslated(a[0], a[1], a[2]);
		get_matrix(a, b, matrix);
		glMultMatrixd(matrix);
		gluCylinder(cylqs, width, width, sqrt((b - a) ^ (b - a)), 4, 2);
		glPopMatrix();
	}

	void Streamline::Draw(int reduced)
	{
		if (reduced)
		{
			glBegin(GL_LINE_STRIP);
			for (unsigned int i = 0; i < points.size() - 1; i++)
			{
				glColor3f(velarr[i + 1] * 0.65, 0.65*(velarr[i + 1] < 0.5 ? velarr[i] : 1.0 - velarr[i]), 0.65*(1 - velarr[i + 1]));
				glVertex3d(points[i][0], points[i][1], points[i][2]);
			}
			glEnd();
		}
		else for (unsigned int i = 0; i < points.size() - 1; i++)
		{
			glColor3f(velarr[i + 1] * 0.65, 0.65*(velarr[i + 1] < 0.5 ? velarr[i] : 1.0 - velarr[i]), 0.65*(1 - velarr[i + 1]));
			drawcylinder(points[i], points[i + 1], 0.25*abs(points[i + 1] - points[i]));
		}
	}

	void Streamline::SVGDraw(std::ostream & file, double modelview[16], double projection[16], int viewport[4])
	{
		for (unsigned int i = 0; i < points.size() - 1; i++)
		{
			double * v0 = points[i].data();
			double * v1 = points[i + 1].data();
			color_t c(velarr[i + 1] * 0.65, 0.65*(velarr[i + 1] < 0.5 ? velarr[i] : 1.0 - velarr[i]), 0.65*(1 - velarr[i + 1]));
			file << "<g stroke=\"" << c.svg_rgb() << "\">" << std::endl;
			svg_line(file, v0[0], v0[1], v0[2], v1[0], v1[1], v1[2], modelview, projection, viewport);
			file << "</g>" << std::endl;
		}
	}
}
<commit_msg>Streamlines in OldDrawGrid<commit_after>#include "streamline.h"
#include "inc_glut.h"
#include "color.h"
#include "svg_line.h"

namespace INMOST
{

	void GetVelocity(Element c, const Tag & velocity_tag, ElementType vel_adj, coord pnt, coord & ret)
	{
		coord cnt;
		const Storage::real eps = 1.0e-8;
		Storage::real dist = 0;
		ret[0] = ret[1] = ret[2] = 0;
		c->Centroid(cnt.data());
		if ((cnt - pnt).length() < 1.0e-5)
		{
			ret = coord(c->RealArray(velocity_tag).data());
		}
		else //inverse distance algorithm (consider wlsqr with linear basis)
		{
			ElementArray<Element> adj = c->BridgeAdjacencies(vel_adj == NODE ? CELL : NODE,vel_adj);
			adj.push_back(c);
			for (ElementArray<Element>::iterator it = adj.begin(); it != adj.end(); ++it)
			{
				it->Centroid(cnt.data());
				coord vel = coord(it->RealArray(velocity_tag).data());
				Storage::real l = (cnt - pnt).length() + eps;
				Storage::real omega = 1.0 / (l*l);
				ret += vel*omega;
				dist += omega;
			}
			ret /= dist;
		}
	}

	Storage::real GetSize(Cell c)
	{
		Storage::real bounds[3][2] = { { 1.0e20, -1.0e20 }, { 1.0e20, -1.0e20 }, { 1.0e20, -1.0e20 } };
		ElementArray<Node> nodes = c->getNodes();
		for (ElementArray<Node>::iterator n = nodes.begin(); n != nodes.end(); ++n)
		{
			Storage::real_array cnt = n->Coords();
			for (int k = 0; k < 3; ++k)
			{
				if (bounds[k][0] > cnt[k]) bounds[k][0] = cnt[k];
				if (bounds[k][1] < cnt[k]) bounds[k][1] = cnt[k];
			}
		}
		Storage::real ret = 1.0e+20;
		for (int k = 0; k < 3; ++k) if (bounds[k][1] - bounds[k][0])
			ret = std::min(ret, bounds[k][1] - bounds[k][0]);
		if (ret > 1.0e+19) std::cout << __FILE__ << ":" << __LINE__ << " oops" << std::endl;
		return ret;
	}

	void GetBbox(Element c, Storage::real bounds[3][2])
	{
		bounds[0][0] = 1.0e20;
		bounds[0][1] = -1.0e20;
		bounds[1][0] = 1.0e20;
		bounds[1][1] = -1.0e20;
		bounds[2][0] = 1.0e20;
		bounds[2][1] = -1.0e20;
		//bounds[3][2] = { { 1.0e20, -1.0e20 }, { 1.0e20, -1.0e20 }, { 1.0e20, -1.0e20 } };
		ElementArray<Node> nodes = c->getNodes();
		for (ElementArray<Node>::iterator n = nodes.begin(); n != nodes.end(); ++n)
		{
			Storage::real_array cnt = n->Coords();
			for (int k = 0; k < 3; ++k)
			{
				if (bounds[k][0] > cnt[k]) bounds[k][0] = cnt[k];
				if (bounds[k][1] < cnt[k]) bounds[k][1] = cnt[k];
			}
		}
		return;
		//Storage::real ret = 1.0e+20;
		//for (int k = 0; k < 3; ++k) if (bounds[k][1] - bounds[k][0])
		//	ret = std::min(ret, bounds[k][1] - bounds[k][0]);
		//if (ret > 1.0e+19) std::cout << __FILE__ << ":" << __LINE__ << " oops" << std::endl;
		//return ret;
	}

	double GetSizeProj(double bounds[3][2], const coord & v)
	{
		double vl = v.length();
		if( !vl ) return 0;
		coord uv = v/vl;
		double ret = 0;
		for(int k = 0; k < 3; ++k) ret += fabs(uv[k]*(bounds[k][1]-bounds[k][0]));
		return ret;
	}

	double GetSizeProj(Element c, const coord & v)
	{
		double bounds[3][2];
		GetBbox(c,bounds);
		return GetSizeProj(bounds,v);
	}

	Storage::real GetSize(Element n, const Tag & size_tag)
	{
		ElementArray<Cell> cells = n->getCells();
		Storage::real minsize = 1.0e+20, size;
		for (ElementArray<Cell>::iterator c = cells.begin(); c != cells.end(); ++c)
		{
			size = c->RealDF(size_tag);
			if (minsize > size) minsize = size;
		}
		if (minsize > 1.0e+19) std::cout << __FILE__ << ":" << __LINE__ << " oops" << std::endl;
		return minsize;
	}

	void BuildStreamlines(Mesh *mesh, Tag vel, ElementType vel_def, std::vector<Streamline> & output)
	{
		if (!vel.isDefined(vel_def))
		{
			std::cout << __FILE__ << ":" << __LINE__ << " Velocity was not defined on " << ElementTypeName(vel_def) << std::endl;
			return;
		}
		if (vel.GetDataType() != DATA_REAL)
		{
			std::cout << __FILE__ << ":" << __LINE__ << " Data type for velocity is not floating point" << std::endl;
			return;
		}
		if (vel.GetSize() != 3)
		{
			std::cout << __FILE__ << ":" << __LINE__ << " Expected 3 entries in velocity field for streamlines" << std::endl;
			return;
		}
		printf("preparing octree around mesh, was sets %d\n", mesh->NumberOfSets());
		Octree octsearch = Octree(mesh->CreateSet("octsearch").first);
		octsearch.Construct(vel_def, false); //auto-detect octree or quadtree
		printf("done, sets %d\n", mesh->NumberOfSets());
		printf("building streamlines\n");
		Tag cell_size = mesh->CreateTag("STREAMLINES_TEMPORARY_CELL_SIZES", DATA_REAL, CELL, NONE, 1);
		Storage::real velmax = 0, velmin = 1.0e20, l;
		for (Mesh::iteratorCell c = mesh->BeginCell(); c != mesh->EndCell(); ++c)
		{
			coord velv(c->RealArray(vel).data());
			l = velv.length();
			if (l > velmax) velmax = l;
			if (l < velmin) velmin = l;
			c->RealDF(cell_size) = GetSize(c->self());
		}
		velmax = log(velmax + 1.0e-25);
		velmin = log(velmin + 1.0e-25);

		{
			MarkerType visited = mesh->CreateMarker();
			int tot = 0;
			int k = 0;
			/*
			printf("started building streamlines from boundary elements\n");

			for (Mesh::iteratorElement f = mesh->BeginElement(vel_def); f != mesh->EndElement(); ++f) if (f->Boundary())
				tot++;

			printf("total elements: %d\n",tot);

			for (Mesh::iteratorElement f = mesh->BeginElement(vel_def); f != mesh->EndElement(); ++f) if (f->Boundary())
			{
				coord v(f->RealArray(vel).data());
				if (v.length() > 1.0e-4)
				{
					coord nrm(0,0,0);
					if( f->GetElementType() == FACE )
						f->getAsFace().UnitNormal(nrm.data());
					else
					{
						coord ncur;
						int nn = 0;
						ElementArray<Face> faces = f->getFaces();
						for (ElementArray<Face>::iterator ff = faces.begin(); ff != faces.end(); ++ff) if (ff->Boundary())
						{
							ff->UnitNormal(ncur.data());
							nrm+=ncur;
							nn++;
						}
						if( nn )
							nrm /= (double)nn;
						else
							std::cout << __FILE__ << ":" << __LINE__ << " No boundary faces around boundary element" << std::endl;
					}
					double dir = nrm^v;
					if( dir > 0.0 ) //velocity points out of mesh
						dir = -1;
					else dir = 1; //velocity points into mesh
					coord cntf;
					f->Centroid(cntf.data());
					output.push_back(Streamline(octsearch, cntf, vel, vel_def, cell_size, velmin, velmax, dir, visited));

					ElementArray<Edge> edges = f->getEdges();
					for (ElementArray<Edge>::iterator n = edges.begin(); n != edges.end(); ++n)
					{
						coord cntn;
						n->Centroid(cntn.data());
						if (cntn[2] == cntf[2])
						{
							const Storage::real coef[4] = { 0.4, 0.8 };
							for (int q = 0; q < 2; ++q)
								output.push_back(Streamline(octsearch, cntf*coef[q] + cntn*(1 - coef[q]), vel, vel_def, cell_size, velmin, velmax, 1.0, visited));
						}
					}
				}
				k++;
				if (k % 100 == 0)
				{
					printf("%5.2f%%\r", (double)k / (double)tot*100.0);
					fflush(stdout);
				}
			}

			printf("done from boundary faces, total streamlines = %lu\n", output.size());
			 */

			printf("started building streamlines from unvisited cells\n");
			tot = 0;
			for (Mesh::iteratorCell it = mesh->BeginCell(); it != mesh->EndCell(); ++it)
				if (!it->GetMarker(visited)) tot++;

			printf("total elements: %d\n", tot);
			k = 0;
			for (Mesh::iteratorCell it = mesh->BeginCell(); it != mesh->EndCell(); ++it)
			{
				if (!it->GetMarker(visited))
				{
					coord cntc;
					it->Centroid(cntc.data());
					if (coord(it->RealArray(vel).data()).length() > 1.0e-4)
					{
						output.push_back(Streamline(octsearch, cntc, vel, vel_def, cell_size, velmin, velmax, 1.0, visited));
						output.push_back(Streamline(octsearch, cntc, vel, vel_def, cell_size, velmin, velmax, -1.0, visited));
					}
				}
				k++;
				if (k % 100 == 0)
				{
					printf("%5.2f%%\r", (double)k / (double)tot*100.0);
					fflush(stdout);
				}
			}
			printf("done from unvisited cells, total streamlines = %lu\n", output.size());

			mesh->ReleaseMarker(visited,vel_def);

		}
		mesh->DeleteTag(cell_size);
		printf("done, total streamlines = %lu\n", output.size());
		printf("killing octree, was sets %d\n", mesh->NumberOfSets());
		octsearch.Destroy();
		printf("done, sets %d\n", mesh->NumberOfSets());

	}

	Streamline::Streamline(const Octree & octsearch, coord pos, Tag velocity_tag, ElementType velocity_defined, Tag cell_size, Storage::real velocity_min, Storage::real velocity_max, Storage::real sign, MarkerType visited)
	{
		Storage::real coef, len, size;
		coord next = pos, vel;
		Element c;
		const int maxsteps = 8000;
		points.reserve(maxsteps / 2);
		velarr.reserve(maxsteps / 2);
		points.push_back(pos);
		velarr.push_back(0);
		while (points.size() < maxsteps)
		{
			c = octsearch.FindClosestCell(next.data());
			if (!c.isValid()) break;
			//if( !c.getAsCell().Inside(next.data()) ) break;
			//check we are inside mesh
			/*
			ElementArray<Cell> cells = c->BridgeAdjacencies2Cell(NODE);
			bool inside = false;
			for (ElementArray<Cell>::iterator it = cells.begin(); it != cells.end() && !inside; ++it)
				if( it->Inside(next.data()) ) inside = true;
			if( !inside ) break;
			*/
			c.SetMarker(visited);
			GetVelocity(c, velocity_tag, velocity_defined, next, vel);
			len = vel.length();
			if (len < 1.0e-7) break;
			//size = GetSize(c, cell_size);// c->RealDF(cell_size);
			size = GetSizeProj(c,vel);
			coef = 0.02*size / len;
			next += vel*coef*sign;
			points.push_back(next);
			velarr.push_back((log(len + 1.0e-25) - velocity_min) / (velocity_max - velocity_min));
		}
		//printf("%ld %ld\n",points.size(),velarr.size());
	}

	GLUquadric * cylqs = NULL;
	void drawcylinder(coord a, coord b, double width)
	{
		double matrix[16];
		if (cylqs == NULL)
		{
			cylqs = gluNewQuadric();
			gluQuadricNormals(cylqs, GLU_SMOOTH);
			gluQuadricOrientation(cylqs, GLU_OUTSIDE);
			gluQuadricDrawStyle(cylqs, GLU_FILL);//GLU_SILHOUETTE
		}
		glPushMatrix();
		glTranslated(a[0], a[1], a[2]);
		get_matrix(a, b, matrix);
		glMultMatrixd(matrix);
		gluCylinder(cylqs, width, width, sqrt((b - a) ^ (b - a)), 4, 2);
		glPopMatrix();
	}

	void Streamline::Draw(int reduced)
	{
		if (reduced)
		{
			glBegin(GL_LINE_STRIP);
			for (unsigned int i = 0; i < points.size() - 1; i++)
			{
				glColor3f(velarr[i + 1] * 0.65, 0.65*(velarr[i + 1] < 0.5 ? velarr[i] : 1.0 - velarr[i]), 0.65*(1 - velarr[i + 1]));
				glVertex3d(points[i][0], points[i][1], points[i][2]);
			}
			glEnd();
		}
		else for (unsigned int i = 0; i < points.size() - 1; i++)
		{
			glColor3f(velarr[i + 1] * 0.65, 0.65*(velarr[i + 1] < 0.5 ? velarr[i] : 1.0 - velarr[i]), 0.65*(1 - velarr[i + 1]));
			drawcylinder(points[i], points[i + 1], 0.5*abs(points[i + 1] - points[i]));
		}
	}

	void Streamline::SVGDraw(std::ostream & file, double modelview[16], double projection[16], int viewport[4])
	{
		for (unsigned int i = 0; i < points.size() - 1; i++)
		{
			double * v0 = points[i].data();
			double * v1 = points[i + 1].data();
			color_t c(velarr[i + 1] * 0.65, 0.65*(velarr[i + 1] < 0.5 ? velarr[i] : 1.0 - velarr[i]), 0.65*(1 - velarr[i + 1]));
			file << "<g stroke=\"" << c.svg_rgb() << "\">" << std::endl;
			svg_line(file, v0[0], v0[1], v0[2], v1[0], v1[1], v1[2], modelview, projection, viewport);
			file << "</g>" << std::endl;
		}
	}
}
<|endoftext|>


<commit_before>#include "inmost.h"

using namespace INMOST;

//TODO:
//attach scale to rescale grid
//attach slice grid to cut cylinder
//option to set shear rate / pressure drop / maximum velocity
//setup BC
//cmake compilation

//setup on mesh:
//
// FORCE - 3 entries
//
// BOUNDARY_CONDITION_VELOCITY - 7 entries
// r = (a5,a6,a7)
// n.(a1*u + a2*t) = n.r
// (I - nn.)(a3*u + a4*t) = (I-nn.)r
//
// BOUNDARY_CONDITION_PRESSURE - 1 entry
//
// REFERENCE_VELOCITY - 3 entries
//
// REFERENCE_PRESSURE - 1 entry
//

typedef Storage::real real;

int main(int argc, char ** argv)
{

	if( argc < 2 )
	{
		std::cout << "Usage: " << argv[0] << " mesh [axis=2 (0:x,1:y,2:z)] [control=0 (0:shear rate,1:pressure drop,2:maximal velocity)] [control_value=10] [visc=1.0e-5] [mesh_out=grid_out.pmf]" << 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;
	}

	std::string fout = "grid_out.pmf";
	int axis = 2;
	double visc = 1.0e-5;
	int control = 0;
	double control_value = 10;
	double Len = 8;
	double Diam = 1;
	double shear = 10;//0; //shear rate
	double dp = 0;//36e-6;
	double vmax = 0;

	if( argc > 2 ) axis = atoi(argv[2]);
	if( argc > 3 ) control = atoi(argv[3]);
	if( argc > 4 ) control_value = atof(argv[4]);
	if( argc > 5 ) visc = atof(argv[5]);
	if( argc > 6 ) fout = std::string(argv[6]);

	if( axis < 0 || axis > 2 )
	{
		std::cout << "bad axis: " << axis << " should be 0 - x, 1 - y, 2 - z" << std::endl;
		return -1;
	}

	if( control < 0 || control > 2 )
	{
		std::cout << "bad control: " << control << " should be 0 - shear rate, 1 - pressure drop, 2 - maximal velocity" << std::endl;
		return -1;
	}

	if( visc <= 0 )
	{
		std::cout << "bad viscosity: " << visc << std::endl;
		return -1;
	}

	if( control == 0 )
	{
		shear = control_value;
		dp = vmax = 0;
	}
	else if( control == 1 )
	{
		dp = control_value;
		shear = vmax = 0;
	}
	else if( control == 2 )
	{
		vmax = control_value;
		dp = shear = 0;
	}

	double cmax[3] = {-1.0e20,-1.0e20,-1.0e20}, cmin[3] = {1.0e20,1.0e20,1.0e20};
	for(Mesh::iteratorNode n = m->BeginNode(); n != m->EndNode(); ++n)
	{
		Storage::real_array c = n->Coords();
		for(int k = 0; k < 3; ++k)
		{
			if( cmax[k] < c[k] ) cmax[k] = c[k];
			if( cmin[k] > c[k] ) cmin[k] = c[k];
		}
	}
	Len = cmax[axis] - cmin[axis];
	Diam = std::max(cmax[(axis+1)%3]-cmin[(axis+1)%3],cmax[(axis+2)%3]-cmin[(axis+2)%3]);

	if( shear )
	{
		dp = 4*Len/Diam*shear*visc;
		vmax = Diam*Diam*dp/(16*visc*Len);
	}
	else if( dp )
	{
		vmax = Diam*Diam*dp/(16*visc*Len);
		shear = 4*vmax/Diam;
	}
	else if( vmax )
	{
		shear = 4*vmax/Diam;
		dp = 4*Len/Diam*shear*visc;
	}

	std::cout << "viscosity " << visc << " shear " << shear << " dp " << dp << " vmax " << vmax << " length " << Len << " diameter " << Diam << std::endl;

	//TagRealArray force = m->CreateTag("FORCE",DATA_REAL,CELL,NONE,3);
	TagRealArray  bc      = m->CreateTag("BOUNDARY_CONDITION_VELOCITY",DATA_REAL,FACE,FACE,7);
	TagReal       bcp     = m->CreateTag("BOUNDARY_CONDITION_PRESSURE",DATA_REAL,FACE,FACE,1);
	TagRealArray  uvw     = m->CreateTag("UVW",DATA_REAL,CELL,NONE,3);
	TagRealArray  uvw_ref = m->CreateTag("REFERENCE_VELOCITY",DATA_REAL,CELL,NONE,3); //depends on viscosity
	TagReal       p_ref   = m->CreateTag("REFERENCE_PRESSURE",DATA_REAL,CELL,NONE,1);
	TagReal       p       = m->CreateTag("P",DATA_REAL,CELL,NONE,1);

	//this should not be needed?
	for(Mesh::iteratorFace it = m->BeginFace(); it != m->EndFace(); ++it) if( it->Boundary() )
		it->FixNormalOrientation();

	double cnt0[3];
	cnt0[axis] = 0;
	cnt0[(axis+1)%2] = (cmax[(axis+1)%2] + cmin[(axis+1)%2])*0.5;
	cnt0[(axis+2)%2] = (cmax[(axis+2)%2] + cmin[(axis+2)%2])*0.5;
	for(Mesh::iteratorCell it = m->BeginCell(); it != m->EndCell(); ++it)
	{
		double cnt[3];
		it->Barycenter(cnt);
		double r = sqrt(pow(cnt[(axis+1)%2]-cnt0[(axis+1)%2],2)+pow(cnt[(axis+2)%2]-cnt0[(axis+2)%2],2));
		uvw(*it,3,1).Zero();
		p[*it] = 0;
		uvw_ref(*it,3,1).Zero();
		uvw_ref(*it,3,1)(axis,0) = (Diam*Diam/4.0-r*r)*dp/(4.0*visc*Len);
		p_ref[*it] = dp*(cnt[axis]-cmin[axis])/Len;
	}

	for(Mesh::iteratorFace it = m->BeginFace(); it != m->EndFace(); ++it) if( it->Boundary() )
	{
		double  n[3];
		it->UnitNormal(n);
		if( fabs(n[axis]-1) < 1.0e-3 ) // outflow
		{
			bcp[*it] = 0+10;
		}
		else if(  fabs(n[axis]+1) < 1.0e-3 ) //inflow
		{
			bcp[*it] = dp+10;
		}
		else //no-slip walls
		{
			bc[*it][0] = 1;
			bc[*it][1] = 0;
			bc[*it][2] = 1;
			bc[*it][3] = 0;
			bc[*it][4] = 0;
			bc[*it][5] = 0;
			bc[*it][6] = 0;
		}
	}

	std::cout << "Saving output to " << fout << std::endl;

	m->Save(fout);

	return 0;
}
<commit_msg>sync N-S pousielle test<commit_after>#include "inmost.h"

using namespace INMOST;

//TODO:
//attach scale to rescale grid
//attach slice grid to cut cylinder
//option to set shear rate / pressure drop / maximum velocity
//setup BC
//cmake compilation

//setup on mesh:
//
// FORCE - 3 entries
//
// BOUNDARY_CONDITION_VELOCITY - 7 entries
// r = (a5,a6,a7)
// n.(a1*u + a2*t) = n.r
// (I - nn.)(a3*u + a4*t) = (I-nn.)r
//
// BOUNDARY_CONDITION_PRESSURE - 1 entry
//
// REFERENCE_VELOCITY - 3 entries
//
// REFERENCE_PRESSURE - 1 entry
//

typedef Storage::real real;

int main(int argc, char ** argv)
{

	if( argc < 2 )
	{
		std::cout << "Usage: " << argv[0] << " mesh [axis=2 (0:x,1:y,2:z)] [control=0 (0:shear rate,1:pressure drop,2:maximal velocity)] [control_value=10] [visc=1.0e-5] [mesh_out=grid_out.pmf] [addsym=0]" << 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;
	}

	std::string fout = "grid_out.pmf";
	int axis = 2;
	double visc = 1.0e-5;
	int control = 0;
	double control_value = 10;
	double Len = 8;
	double Diam = 1;
	double shear = 10;//0; //shear rate
	double dp = 0;//36e-6;
	double vmax = 0;
	double addsym = 0;

	if( argc > 2 ) axis = atoi(argv[2]);
	if( argc > 3 ) control = atoi(argv[3]);
	if( argc > 4 ) control_value = atof(argv[4]);
	if( argc > 5 ) visc = atof(argv[5]);
	if( argc > 6 ) fout = std::string(argv[6]);
	if( argc > 7 ) addsym = atof(argv[7]);

	if( axis < 0 || axis > 2 )
	{
		std::cout << "bad axis: " << axis << " should be 0 - x, 1 - y, 2 - z" << std::endl;
		return -1;
	}

	if( control < 0 || control > 2 )
	{
		std::cout << "bad control: " << control << " should be 0 - shear rate, 1 - pressure drop, 2 - maximal velocity" << std::endl;
		return -1;
	}

	if( visc <= 0 )
	{
		std::cout << "bad viscosity: " << visc << std::endl;
		return -1;
	}

	if( control == 0 )
	{
		shear = control_value;
		dp = vmax = 0;
	}
	else if( control == 1 )
	{
		dp = control_value;
		shear = vmax = 0;
	}
	else if( control == 2 )
	{
		vmax = control_value;
		dp = shear = 0;
	}

	double cmax[3] = {-1.0e20,-1.0e20,-1.0e20}, cmin[3] = {1.0e20,1.0e20,1.0e20};
	for(Mesh::iteratorNode n = m->BeginNode(); n != m->EndNode(); ++n)
	{
		Storage::real_array c = n->Coords();
		for(int k = 0; k < 3; ++k)
		{
			if( cmax[k] < c[k] ) cmax[k] = c[k];
			if( cmin[k] > c[k] ) cmin[k] = c[k];
		}
	}
	Len = cmax[axis] - cmin[axis];
	Diam = std::max(cmax[(axis+1)%3]-cmin[(axis+1)%3],cmax[(axis+2)%3]-cmin[(axis+2)%3]);

	if( shear )
	{
		dp = 4*Len/Diam*shear*visc;
		vmax = Diam*Diam*dp/(16*visc*Len);
	}
	else if( dp )
	{
		vmax = Diam*Diam*dp/(16*visc*Len);
		shear = 4*vmax/Diam;
	}
	else if( vmax )
	{
		shear = 4*vmax/Diam;
		dp = 4*Len/Diam*shear*visc;
	}

	std::cout << "viscosity " << visc << " shear " << shear << " dp " << dp << " vmax " << vmax << " length " << Len << " diameter " << Diam << std::endl;

	//TagRealArray force = m->CreateTag("FORCE",DATA_REAL,CELL,NONE,3);
	TagRealArray  bc      = m->CreateTag("BOUNDARY_CONDITION_VELOCITY",DATA_REAL,FACE,FACE,7);
	TagReal       bcp     = m->CreateTag("BOUNDARY_CONDITION_PRESSURE",DATA_REAL,FACE,FACE,1);
	TagRealArray  uvw     = m->CreateTag("UVW",DATA_REAL,CELL,NONE,3);
	TagRealArray  uvw_ref = m->CreateTag("REFERENCE_VELOCITY",DATA_REAL,CELL,NONE,3); //depends on viscosity
	TagReal       p_ref   = m->CreateTag("REFERENCE_PRESSURE",DATA_REAL,CELL,NONE,1);
	TagReal       p       = m->CreateTag("P",DATA_REAL,CELL,NONE,1);

	//this should not be needed?
	for(Mesh::iteratorFace it = m->BeginFace(); it != m->EndFace(); ++it) if( it->Boundary() )
		it->FixNormalOrientation();

	double cnt0[3], p0 = 10;
	cnt0[axis] = 0;
	cnt0[(axis+1)%2] = (cmax[(axis+1)%2] + cmin[(axis+1)%2])*0.5;
	cnt0[(axis+2)%2] = (cmax[(axis+2)%2] + cmin[(axis+2)%2])*0.5;
	std::cout << "center " << cnt0[0] << " " << cnt0[1] << " " << cnt0[2] << std::endl;

	for(Mesh::iteratorCell it = m->BeginCell(); it != m->EndCell(); ++it)
	{
		double cnt[3];
		it->Barycenter(cnt);
		double r = sqrt(pow(cnt[(axis+1)%2]-cnt0[(axis+1)%2],2)+pow(cnt[(axis+2)%2]-cnt0[(axis+2)%2],2));
		uvw(*it,3,1).Zero();
		p[*it] = 0;
		uvw_ref(*it,3,1).Zero();
		uvw_ref(*it,3,1)(axis,0) = (Diam*Diam/4.0-r*r)*dp/(4.0*visc*Len);
		p_ref[*it] = p0 + dp*(cmax[axis] - cnt[axis])/Len - 0.5*addsym*uvw_ref(*it,3,1).DotProduct(uvw_ref(*it,3,1));
	}

	for(Mesh::iteratorFace it = m->BeginFace(); it != m->EndFace(); ++it) if( it->Boundary() )
	{
		double  n[3];
		it->UnitNormal(n);
		if( fabs(n[axis]-1) < 1.0e-3 ) // outflow
		{
			bcp[*it] = 0+p0;
		}
		else if(  fabs(n[axis]+1) < 1.0e-3 ) //inflow
		{
			bcp[*it] = dp+p0;
		}
		else //no-slip walls
		{
			bc[*it][0] = 1;
			bc[*it][1] = 0;
			bc[*it][2] = 1;
			bc[*it][3] = 0;
			bc[*it][4] = 0;
			bc[*it][5] = 0;
			bc[*it][6] = 0;
		}
	}

	std::cout << "Saving output to " << fout << std::endl;

	m->Save(fout);

	return 0;
}
<|endoftext|>


<commit_before>/** @copyright
 * Copyright (c) 2018, Stuart W Baker
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are  permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @file TivaCanNullTx.hxx
 * This file implements a test driver for CAN on Tiva.
 *
 * @author Stuart W. Baker
 * @date 6 June 2018
 */

#ifndef _FREERTOS_DRIVERS_TI_TIVACANNULLTX_HXX_
#define _FREERTOS_DRIVERS_TI_TIVACANNULLTX_HXX_

#include "TivaDev.hxx"

/** Specialization of Tiva CAN driver for testing purposes.
 */
class TivaCanNullTx : public TivaCan
{
public:
    /** Constructor.
     * @param name name of this device instance in the file system
     * @param base base address of this device
     * @param interrupt interrupt number of this device
     */
    TivaCanNullTx(const char *name, unsigned long base, uint32_t interrupt)
        : TivaCan(name, base, interrupt)
        , readTimeFirst_(0)
        , readTime10000_(0)
        , readCount_(0)
    {
    }

    /** Destructor.
     */
    ~TivaCanNullTx()
    {
    }

    /** Get the latest performance time stamp.
     * @param count the number of messages that have been received in total
     * @return if count < @ref MESSAGE_COUNT, the time since the first message
     *         was received, else, the time between the first message received
     *         and the 10,000th message received.
     */
    long long get_timestamp_and_count(unsigned *count)
    {
        long long result;

        portENTER_CRITICAL();
        *count = readCount_;
        if (readCount_ >= MESSAGE_COUNT)
        {
            result = readTime10000_ - readTimeFirst_;
        }
        else
        {
            result = OSTime::get_monotonic() - readTimeFirst_;
        }
        portEXIT_CRITICAL();

        return result;
    }

private:
    static constexpr size_t MESSAGE_COUNT = 10000;

    /** Read from a file or device.
    * @param file file reference for this device
    * @param buf location to place read data
    * @param count number of bytes to read
    * @return number of bytes read upon success, -1 upon failure with errno
    *         containing the cause
    */
    ssize_t read(File *file, void *buf, size_t count) override
    {
        if (readCount_ == 0)
        {
            readTimeFirst_ = OSTime::get_monotonic();
        }

        ssize_t result = Can::read(file, buf, count);

        if (result > 0)
        {
            readCount_ += result / sizeof(struct can_frame);

            if (readCount_ >= MESSAGE_COUNT && readTime10000_ == 0)
            {
                readTime10000_ = OSTime::get_monotonic();
            }
        }

        return result;
    }

    /** Write to a file or device.
    * @param file file reference for this device
    * @param buf location to find write data
    * @param count number of bytes to write
    * @return number of bytes written upon success, -1 upon failure with errno
    *         containing the cause
    */
    ssize_t write(File *file, const void *buf, size_t count) override
    {
        /* drop all the write data on the floor */
        return count;
    }

    long long readTimeFirst_; /**< timestamp of first read in nsec */
    long long readTime10000_; /**< timestamp of 10,000th read in nsec */

    size_t readCount_; /**< running count of all the reads */

    DISALLOW_COPY_AND_ASSIGN(TivaCanNullTx);
};

#endif /* _FREERTOS_DRIVERS_TI_TIVACANNULLTX_HXX_ */
<commit_msg>Fix the logic to be more time accurate.<commit_after>/** @copyright
 * Copyright (c) 2018, Stuart W Baker
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are  permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @file TivaCanNullTx.hxx
 * This file implements a test driver for CAN on Tiva.
 *
 * @author Stuart W. Baker
 * @date 6 June 2018
 */

#ifndef _FREERTOS_DRIVERS_TI_TIVACANNULLTX_HXX_
#define _FREERTOS_DRIVERS_TI_TIVACANNULLTX_HXX_

#include "TivaDev.hxx"

/** Specialization of Tiva CAN driver for testing purposes.
 */
class TivaCanNullTx : public TivaCan
{
public:
    /** Constructor.
     * @param name name of this device instance in the file system
     * @param base base address of this device
     * @param interrupt interrupt number of this device
     */
    TivaCanNullTx(const char *name, unsigned long base, uint32_t interrupt)
        : TivaCan(name, base, interrupt)
        , readTimeFirst_(0)
        , readTime10000_(0)
        , readCount_(0)
    {
    }

    /** Destructor.
     */
    ~TivaCanNullTx()
    {
    }

    /** Get the latest performance time stamp.
     * @param count the number of messages that have been received in total
     * @return if count < @ref MESSAGE_COUNT, the time since the first message
     *         was received, else, the time between the first message received
     *         and the 10,000th message received.
     */
    long long get_timestamp_and_count(unsigned *count)
    {
        long long result;

        portENTER_CRITICAL();
        *count = readCount_;
        if (readCount_ >= MESSAGE_COUNT)
        {
            result = readTime10000_ - readTimeFirst_;
        }
        else
        {
            result = OSTime::get_monotonic() - readTimeFirst_;
        }
        portEXIT_CRITICAL();

        return result;
    }

private:
    static constexpr size_t MESSAGE_COUNT = 10000;

    /** Read from a file or device.
    * @param file file reference for this device
    * @param buf location to place read data
    * @param count number of bytes to read
    * @return number of bytes read upon success, -1 upon failure with errno
    *         containing the cause
    */
    ssize_t read(File *file, void *buf, size_t count) override
    {
        ssize_t result = Can::read(file, buf, count);

        if (result > 0)
        {
            if (readCount_ == 0)
            {
                readTimeFirst_ = OSTime::get_monotonic();
            }

            readCount_ += result / sizeof(struct can_frame);

            if (readCount_ >= MESSAGE_COUNT && readTime10000_ == 0)
            {
                readTime10000_ = OSTime::get_monotonic();
            }
        }

        return result;
    }

    /** Write to a file or device.
    * @param file file reference for this device
    * @param buf location to find write data
    * @param count number of bytes to write
    * @return number of bytes written upon success, -1 upon failure with errno
    *         containing the cause
    */
    ssize_t write(File *file, const void *buf, size_t count) override
    {
        /* drop all the write data on the floor */
        return count;
    }

    long long readTimeFirst_; /**< timestamp of first read in nsec */
    long long readTime10000_; /**< timestamp of 10,000th read in nsec */

    size_t readCount_; /**< running count of all the reads */

    DISALLOW_COPY_AND_ASSIGN(TivaCanNullTx);
};

#endif /* _FREERTOS_DRIVERS_TI_TIVACANNULLTX_HXX_ */
<|endoftext|>


<commit_before>//..............................................................................
//
//  This file is part of the Jancy toolkit.
//
//  Jancy is distributed under the MIT license.
//  For details see accompanying license.txt file,
//  the public copy of which is also available at:
//  http://tibbo.com/downloads/archive/jancy/license.txt
//
//..............................................................................

#include "pch.h"
#include "jnc_io_ChildProcess.h"
#include "jnc_io_IoLib.h"

namespace jnc {
namespace io {

//..............................................................................

#if (_JNC_OS_WIN)
bool
createStdioPipe(
	handle_t* readHandle,
	handle_t* writeHandle,
	dword_t readMode,
	dword_t writeMode
	)
{
	static int32_t pipeId = 0;

	char buffer[256];wait pid timeout
	sl::String_w pipeName(ref::BufKind_Stack, buffer, sizeof(buffer));
	pipeName.format(
		L"\\\\.\\pipe\\jnc.ChildProcess.%p.%d",
		sys::getCurrentProcessId(),
		sys::atomicInc(&pipeId)
		);

	axl::io::win::NamedPipe pipe;
	axl::io::win::File file;

	SECURITY_ATTRIBUTES secAttr = { 0 };
	secAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
	secAttr.bInheritHandle = true;

	bool result =
		pipe.create(
			pipeName,
			PIPE_ACCESS_INBOUND | readMode,
			PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
			1,
			0, 0, 0,
			&secAttr
			) &&
		file.create(
			pipeName,
			GENERIC_WRITE,
			0,
			&secAttr,
			OPEN_EXISTING,
			writeMode
			);

	if (!result)
		return false;

	*readHandle = pipe.detach();
	*writeHandle = file.detach();
	return true;
}
#else
bool
exec(const char* commandLine)
{
	char buffer[256];
	sl::Array<char*> argv(ref::BufKind_Stack, buffer, sizeof(buffer));

	sl::String string = commandLine;

	size_t length = string.getLength();
	for (;;)
	{
		string.trimLeft();
		if (string.isEmpty())
			break;

		argv.append(string.p());

		size_t pos = string.findOneOf(sl::StringDetails::getWhitespace());
		if (pos == -1)
			break;

		string[pos] = 0;
		string = string.getSubString(pos + 1);
	}

	if (argv.isEmpty())
	{
		err::setError("empty command line");
		return false;
	}

	argv.append(NULL);
	int result = ::execvp(argv[0], argv.p());
	ASSERT(result == -1);
	err::setLastSystemError();
	return false;
}
#endif

//..............................................................................

JNC_DEFINE_OPAQUE_CLASS_TYPE(
	ChildProcess,
	"io.ChildProcess",
	g_ioLibGuid,
	IoLibCacheSlot_ChildProcess,
	ChildProcess,
	NULL
	)

JNC_BEGIN_TYPE_FUNCTION_MAP(ChildProcess)
	JNC_MAP_CONSTRUCTOR(&jnc::construct<ChildProcess>)
	JNC_MAP_DESTRUCTOR(&jnc::destruct<ChildProcess>)
	JNC_MAP_FUNCTION("start", &ChildProcess::start)
	JNC_MAP_FUNCTION("close", &ChildProcess::close)
	JNC_MAP_FUNCTION("wait", &ChildProcess::wait)
	JNC_MAP_FUNCTION("waitAndClose", &ChildProcess::waitAndClose)
	JNC_MAP_FUNCTION("terminate", &ChildProcess::terminate)
JNC_END_TYPE_FUNCTION_MAP()

//..............................................................................

ChildProcess::ChildProcess()
{
	jnc::construct<FileStream>(m_stdin);
	jnc::construct<FileStream>(m_stdout);
	jnc::construct<FileStream>(m_stderr);
}

ChildProcess::~ChildProcess()
{
	close();
}

bool
JNC_CDECL
ChildProcess::start(
	DataPtr commandLinePtr,
	uint_t flags
	)
{
	close();

	bool isMergedStdoutStderr = (flags & ChildProcessFlag_MergeStdoutStderr) != 0;

#if (_JNC_OS_WIN)
	sl::String_w cmdLine = (char*)commandLinePtr.m_p;

	bool_t result;

	axl::io::win::File parentStdin;
	axl::io::win::File parentStdout;
	axl::io::win::File parentStderr;
	axl::io::win::File childStdin;
	axl::io::win::File childStdout;
	axl::io::win::File childStderr;

	result =
		createStdioPipe(childStdin.p(), parentStdin.p(), 0, FILE_FLAG_OVERLAPPED) &&
		createStdioPipe(parentStdout.p(), childStdout.p(), FILE_FLAG_OVERLAPPED, 0) &&
		(isMergedStdoutStderr || createStdioPipe(parentStderr.p(), childStderr.p(), FILE_FLAG_OVERLAPPED, 0));

	if (!result)
		return false;

	STARTUPINFOW startupInfo = { 0 };
	startupInfo.cb = sizeof(STARTUPINFO);
	startupInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
	startupInfo.hStdInput = childStdin;
	startupInfo.hStdOutput = childStdout;
	startupInfo.hStdError = isMergedStdoutStderr ? childStdout : childStderr;
	startupInfo.wShowWindow = SW_HIDE;

	result = m_process.createProcess(cmdLine, true, CREATE_NEW_CONSOLE, &startupInfo);
	if (!result)
		return false;

	attachFileStream(m_stdin, &parentStdin);
	attachFileStream(m_stdout, &parentStdout);
	attachFileStream(m_stderr, &parentStderr);
#else
	axl::io::psx::Pipe stdinPipe;
	axl::io::psx::Pipe stdoutPipe;
	axl::io::psx::Pipe stderrPipe;

	bool result =
		stdinPipe.create() &&
		stdinPipe.m_writeFile.setBlockingMode(false) &&
		stdoutPipe.create() &&
		stdoutPipe.m_readFile.setBlockingMode(false) &&
		(isMergedStdoutStderr ||
		stderrPipe.create() &&
		stderrPipe.m_readFile.setBlockingMode(false));

	if (!result)
		return false;

	pid_t pid = ::fork();
	switch (pid)
	{
	case -1:
		err::setLastSystemError();
		return false;

	case 0:
		::dup2(stdinPipe.m_readFile, STDIN_FILENO);
		::dup2(stdoutPipe.m_writeFile, STDOUT_FILENO);
		::dup2(isMergedStdoutStderr ? stdoutPipe.m_writeFile : stderrPipe.m_writeFile, STDERR_FILENO);

		exec((char*)commandLinePtr.m_p);

		::fprintf(stderr, "POSIX exec error: %s\n", err::getLastErrorDescription().sz());
		::abort();
		ASSERT(false);

	default:
		m_pid = pid;
	}

	attachFileStream(m_stdin, &stdinPipe.m_writeFile);
	attachFileStream(m_stdout, &stdoutPipe.m_readFile);
	attachFileStream(m_stderr, &stderrPipe.m_readFile);
#endif

	return true;
}

void
JNC_CDECL
ChildProcess::close()
{
	m_stdin->close();
	m_stdout->close();
	m_stderr->close();
#if (_JNC_OS_WIN)
	m_process.close();
#endif
}

uint_t
JNC_CDECL
ChildProcess::getExitCode()
{
#if (_JNC_OS_WIN)
	dword_t exitCode = 0;
	m_process.getExitCode(&exitCode);
	return exitCode;
#endif
	return 0;
}

bool
JNC_CDECL
ChildProcess::wait(uint_t timeout)
{
	return true;
}

void
JNC_CDECL
ChildProcess::waitAndClose(uint_t timeout)
{
	close();
}

bool
JNC_CDECL
ChildProcess::terminate()
{
	return true;
}

void
ChildProcess::attachFileStream(
	io::FileStream* fileStream,
	AxlOsFile* file
	)
{
	fileStream->close();

	if (!file->isOpen())
		return;

	fileStream->m_file.m_file.attach(file->detach());
	fileStream->m_fileStreamKind = FileStreamKind_Pipe;
/*	fileStream->setReadParallelism(m_readParallelism);
	fileStream->setReadBlockSize(m_readBlockSize);
	fileStream->setReadBufferSize(m_readBufferSize);
	fileStream->setWriteBufferSize(m_writeBufferSize);
	fileStream->setOptions(m_options); */
#if (_JNC_OS_WIN)
	ASSERT(!fileStream->m_overlappedIo);
	fileStream->m_overlappedIo = AXL_MEM_NEW(FileStream::OverlappedIo);
#else
#endif
	fileStream->AsyncIoDevice::open();
	fileStream->m_ioThread.start();
}

//..............................................................................

} // namespace io
} // namespace jnc
<commit_msg>[jnc_io] added proper handling for execvp success/failure (via a dedicated pipe with FD_CLOEXEC)<commit_after>//..............................................................................
//
//  This file is part of the Jancy toolkit.
//
//  Jancy is distributed under the MIT license.
//  For details see accompanying license.txt file,
//  the public copy of which is also available at:
//  http://tibbo.com/downloads/archive/jancy/license.txt
//
//..............................................................................

#include "pch.h"
#include "jnc_io_ChildProcess.h"
#include "jnc_io_IoLib.h"

namespace jnc {
namespace io {

//..............................................................................

#if (_JNC_OS_WIN)
bool
createStdioPipe(
	handle_t* readHandle,
	handle_t* writeHandle,
	dword_t readMode,
	dword_t writeMode
	)
{
	static int32_t pipeId = 0;

	char buffer[256];wait pid timeout
	sl::String_w pipeName(ref::BufKind_Stack, buffer, sizeof(buffer));
	pipeName.format(
		L"\\\\.\\pipe\\jnc.ChildProcess.%p.%d",
		sys::getCurrentProcessId(),
		sys::atomicInc(&pipeId)
		);

	axl::io::win::NamedPipe pipe;
	axl::io::win::File file;

	SECURITY_ATTRIBUTES secAttr = { 0 };
	secAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
	secAttr.bInheritHandle = true;

	bool result =
		pipe.create(
			pipeName,
			PIPE_ACCESS_INBOUND | readMode,
			PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
			1,
			0, 0, 0,
			&secAttr
			) &&
		file.create(
			pipeName,
			GENERIC_WRITE,
			0,
			&secAttr,
			OPEN_EXISTING,
			writeMode
			);

	if (!result)
		return false;

	*readHandle = pipe.detach();
	*writeHandle = file.detach();
	return true;
}
#else
void
exec(const char* commandLine) // returns on failure only
{
	char buffer[256];
	sl::Array<char*> argv(ref::BufKind_Stack, buffer, sizeof(buffer));

	sl::String string = commandLine;

	size_t length = string.getLength();
	for (;;)
	{
		string.trimLeft();
		if (string.isEmpty())
			break;

		argv.append(string.p());

		size_t pos = string.findOneOf(sl::StringDetails::getWhitespace());
		if (pos == -1)
			break;

		string[pos] = 0;
		string = string.getSubString(pos + 1);
	}

	if (argv.isEmpty())
	{
		err::setError("empty command line");
		return;
	}

	argv.append(NULL);

	int result = ::execvp(argv[0], argv.p());
	ASSERT(result == -1);
	err::setLastSystemError();
}
#endif

//..............................................................................

JNC_DEFINE_OPAQUE_CLASS_TYPE(
	ChildProcess,
	"io.ChildProcess",
	g_ioLibGuid,
	IoLibCacheSlot_ChildProcess,
	ChildProcess,
	NULL
	)

JNC_BEGIN_TYPE_FUNCTION_MAP(ChildProcess)
	JNC_MAP_CONSTRUCTOR(&jnc::construct<ChildProcess>)
	JNC_MAP_DESTRUCTOR(&jnc::destruct<ChildProcess>)
	JNC_MAP_FUNCTION("start", &ChildProcess::start)
	JNC_MAP_FUNCTION("close", &ChildProcess::close)
	JNC_MAP_FUNCTION("wait", &ChildProcess::wait)
	JNC_MAP_FUNCTION("waitAndClose", &ChildProcess::waitAndClose)
	JNC_MAP_FUNCTION("terminate", &ChildProcess::terminate)
JNC_END_TYPE_FUNCTION_MAP()

//..............................................................................

ChildProcess::ChildProcess()
{
	jnc::construct<FileStream>(m_stdin);
	jnc::construct<FileStream>(m_stdout);
	jnc::construct<FileStream>(m_stderr);
}

ChildProcess::~ChildProcess()
{
	close();
}

bool
JNC_CDECL
ChildProcess::start(
	DataPtr commandLinePtr,
	uint_t flags
	)
{
	close();

	bool isMergedStdoutStderr = (flags & ChildProcessFlag_MergeStdoutStderr) != 0;

#if (_JNC_OS_WIN)
	sl::String_w cmdLine = (char*)commandLinePtr.m_p;

	bool_t result;

	axl::io::win::File parentStdin;
	axl::io::win::File parentStdout;
	axl::io::win::File parentStderr;
	axl::io::win::File childStdin;
	axl::io::win::File childStdout;
	axl::io::win::File childStderr;

	result =
		createStdioPipe(childStdin.p(), parentStdin.p(), 0, FILE_FLAG_OVERLAPPED) &&
		createStdioPipe(parentStdout.p(), childStdout.p(), FILE_FLAG_OVERLAPPED, 0) &&
		(isMergedStdoutStderr || createStdioPipe(parentStderr.p(), childStderr.p(), FILE_FLAG_OVERLAPPED, 0));

	if (!result)
		return false;

	STARTUPINFOW startupInfo = { 0 };
	startupInfo.cb = sizeof(STARTUPINFO);
	startupInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
	startupInfo.hStdInput = childStdin;
	startupInfo.hStdOutput = childStdout;
	startupInfo.hStdError = isMergedStdoutStderr ? childStdout : childStderr;
	startupInfo.wShowWindow = SW_HIDE;

	result = m_process.createProcess(cmdLine, true, CREATE_NEW_CONSOLE, &startupInfo);
	if (!result)
		return false;

	attachFileStream(m_stdin, &parentStdin);
	attachFileStream(m_stdout, &parentStdout);
	attachFileStream(m_stderr, &parentStderr);
#else
	axl::io::psx::Pipe stdinPipe;
	axl::io::psx::Pipe stdoutPipe;
	axl::io::psx::Pipe stderrPipe;
	axl::io::psx::Pipe execPipe;

	bool result =
		stdinPipe.create() &&
		stdinPipe.m_writeFile.setBlockingMode(false) &&
		stdoutPipe.create() &&
		stdoutPipe.m_readFile.setBlockingMode(false) &&
		(isMergedStdoutStderr ||
		stderrPipe.create() &&
		stderrPipe.m_readFile.setBlockingMode(false)) &&
		execPipe.create();

	if (!result)
		return false;

	execPipe.m_writeFile.fcntl(F_SETFD, FD_CLOEXEC);

	err::Error error;

	pid_t pid = ::fork();
	switch (pid)
	{
	case -1:
		err::setLastSystemError();
		return false;

	case 0:
		::dup2(stdinPipe.m_readFile, STDIN_FILENO);
		::dup2(stdoutPipe.m_writeFile, STDOUT_FILENO);
		::dup2(isMergedStdoutStderr ? stdoutPipe.m_writeFile : stderrPipe.m_writeFile, STDERR_FILENO);

		exec((char*)commandLinePtr.m_p);

		error = err::getLastError();
		execPipe.m_writeFile.write(error, error->m_size);
		execPipe.m_writeFile.flush();

		::_exit(-1);
		ASSERT(false);

	default:
		execPipe.m_writeFile.close();

		fd_set rdset;
		FD_ZERO(&rdset);
		FD_SET(execPipe.m_readFile, &rdset);

		char buffer[256];
		size_t size = execPipe.m_readFile.read(buffer, sizeof(buffer));
		if (size == 0 || size == -1)
		{
			m_pid = pid;
			break;
		}

		if (((err::ErrorHdr*)buffer)->m_size == size)
			err::setError((err::ErrorHdr*)buffer);
		else
			err::setError("POSIX execvp failed"); // unlikely fallback

		return false;
	}

	attachFileStream(m_stdin, &stdinPipe.m_writeFile);
	attachFileStream(m_stdout, &stdoutPipe.m_readFile);
	attachFileStream(m_stderr, &stderrPipe.m_readFile);
#endif

	return true;
}

void
JNC_CDECL
ChildProcess::close()
{
	m_stdin->close();
	m_stdout->close();
	m_stderr->close();
#if (_JNC_OS_WIN)
	m_process.close();
#endif
}

uint_t
JNC_CDECL
ChildProcess::getExitCode()
{
#if (_JNC_OS_WIN)
	dword_t exitCode = 0;
	m_process.getExitCode(&exitCode);
	return exitCode;
#endif
	return 0;
}

bool
JNC_CDECL
ChildProcess::wait(uint_t timeout)
{
	return true;
}

void
JNC_CDECL
ChildProcess::waitAndClose(uint_t timeout)
{
	close();
}

bool
JNC_CDECL
ChildProcess::terminate()
{
	return true;
}

void
ChildProcess::attachFileStream(
	io::FileStream* fileStream,
	AxlOsFile* file
	)
{
	fileStream->close();

	if (!file->isOpen())
		return;

	fileStream->m_file.m_file.attach(file->detach());
	fileStream->m_fileStreamKind = FileStreamKind_Pipe;
/*	fileStream->setReadParallelism(m_readParallelism);
	fileStream->setReadBlockSize(m_readBlockSize);
	fileStream->setReadBufferSize(m_readBufferSize);
	fileStream->setWriteBufferSize(m_writeBufferSize);
	fileStream->setOptions(m_options); */
#if (_JNC_OS_WIN)
	ASSERT(!fileStream->m_overlappedIo);
	fileStream->m_overlappedIo = AXL_MEM_NEW(FileStream::OverlappedIo);
#endif
	fileStream->AsyncIoDevice::open();
	fileStream->m_ioThread.start();
}

//..............................................................................

} // namespace io
} // namespace jnc
<|endoftext|>


<commit_before>/* -*-  mode: c++; indent-tabs-mode: nil -*- */

/*
  The thaw depth evaluator gets the subsurface temperature.
  This computes the thaw depth over time.
  This is SecondaryVariablesFieldEvaluator and depends on the subsurface temperature,

  Authors: Ahmad Jan (jana@ornl.gov)
*/

#ifndef AMANZI_FLOWRELATIONS_INITIAL_ELEV_EVALUATOR_
#define AMANZI_FLOWRELATIONS_INITIAL_ELVE_EVALUATOR_

#include "Factory.hh"
#include "secondary_variable_field_evaluator.hh"

namespace Amanzi {
namespace Flow {

class InitialElevationEvaluator : public SecondaryVariableFieldEvaluator {

public:
  explicit
  InitialElevationEvaluator(Teuchos::ParameterList& plist);
  InitialElevationEvaluator(const InitialElevationEvaluator& other);
  Teuchos::RCP<FieldEvaluator> Clone() const;

protected:
  // Required methods from SecondaryVariableFieldEvaluator
  virtual void EvaluateField_(const Teuchos::Ptr<State>& S,
                              const Teuchos::Ptr<CompositeVector>& result);
  virtual void EvaluateFieldPartialDerivative_(const Teuchos::Ptr<State>& S,
               Key wrt_key, const Teuchos::Ptr<CompositeVector>& result);

  virtual bool HasFieldChanged(const Teuchos::Ptr<State>& S, Key request);

  virtual void EnsureCompatibility(const Teuchos::Ptr<State>& S);

  bool updated_once_;
  Key domain_;
  Key bp_key_;
private:
  static Utils::RegisteredFactory<FieldEvaluator,InitialElevationEvaluator> reg_;

};

} //namespace
} //namespace

#endif
<commit_msg>fixes mismatched pragma hh protection<commit_after>/* -*-  mode: c++; indent-tabs-mode: nil -*- */

/*
  The thaw depth evaluator gets the subsurface temperature.
  This computes the thaw depth over time.
  This is SecondaryVariablesFieldEvaluator and depends on the subsurface temperature,

  Authors: Ahmad Jan (jana@ornl.gov)
*/

#pragma once

#include "Factory.hh"
#include "secondary_variable_field_evaluator.hh"

namespace Amanzi {
namespace Flow {

class InitialElevationEvaluator : public SecondaryVariableFieldEvaluator {

public:
  explicit
  InitialElevationEvaluator(Teuchos::ParameterList& plist);
  InitialElevationEvaluator(const InitialElevationEvaluator& other);
  Teuchos::RCP<FieldEvaluator> Clone() const;

protected:
  // Required methods from SecondaryVariableFieldEvaluator
  virtual void EvaluateField_(const Teuchos::Ptr<State>& S,
                              const Teuchos::Ptr<CompositeVector>& result);
  virtual void EvaluateFieldPartialDerivative_(const Teuchos::Ptr<State>& S,
               Key wrt_key, const Teuchos::Ptr<CompositeVector>& result);

  virtual bool HasFieldChanged(const Teuchos::Ptr<State>& S, Key request);

  virtual void EnsureCompatibility(const Teuchos::Ptr<State>& S);

  bool updated_once_;
  Key domain_;
  Key bp_key_;
private:
  static Utils::RegisteredFactory<FieldEvaluator,InitialElevationEvaluator> reg_;

};

} //namespace
} //namespace

<|endoftext|>