<commit_before>#include <iomanip>
#include <boost/format.hpp>

#include "prefix.hpp"
#include "util.hpp"
#include "stream.hpp"
#include "streamindent.hpp"
#include "printing.hpp"
#include "Function.hpp"

#include <regex>

namespace autobind {

namespace
{
	const boost::format FunctionPrototype{
		"static PyObject *%s(%s *self, PyObject *args, PyObject *kw)"
	};

}

std::string processDocString(const std::string &docstring)
{
	auto result = std::regex_replace(docstring, std::regex("(^|\n)\\s*(///|\\*)"), "$1");
	replace(result, "\\", "\\\\");
	replace(result, "\n", "\\n");
	replace(result, "\"", "\\\"");

	return result;
}

Function::Function(std::string name, std::vector<Arg> args,
                   std::string docstring)
: Export(std::move(name))
, _args(std::move(args))
, _docstring(std::move(docstring))
{
	auto parts = rsplit(this->name(), "::");
	_unqualifiedName = parts.second;
	_implName = this->name();
	replace(_implName, "::", "_ns_");
	_implName += "_py_bind_impl";

}

void Function::codegenCall(std::ostream &out) const
{
	out << name();
	codegenCallArgs(out);
	out << ";\n";
}

void Function::codegenCallArgs(std::ostream &out) const
{

	using namespace streams;

	auto argStream = stream(_args)
		| enumerated()
		| pairTransformed([](int i, const Arg &a) {
			return a.requiresAdditionalConversion?
				  str(boost::format("PyConversion<%1%>::load(arg%2%)") % a.cppQualTypeName % i)
				: str(boost::format("arg%1%") % i);
		})
		| interposed(", ");

	out << "(" << cat(argStream) << ")";
}

void Function::codegenDeclaration(std::ostream &out) const
{
	out << boost::format(FunctionPrototype) % _implName % selfTypeName() << ";\n";
}

void Function::codegenTupleUnpack(std::ostream &out) const
{
	using namespace streams;
	// declare variables
	for(const auto &pair : stream(_args) | enumerated())
	{
		if(pair.second.requiresAdditionalConversion)
		{
			out << "PyObject *";
		}
		else
		{
			out << pair.second.cppQualTypeName << " ";
		}

		out << "arg" << pair.first << ";\n";
	}

	// call PyArg_ParseTuple
	auto kwlistStream = stream(_args)
		| transformed([](const Arg &a) { return "\"" + a.argName + "\", "; });

	out << boost::format("static const char *kwlist[] = {%1%0};\n") % cat(kwlistStream);

	auto argStream = count()
		| take(_args.size())
		| transformed([](int i) { return boost::format(", &arg%d") % i; });

	auto formatStream = stream(_args)
		| transformed([](const Arg &a) { return a.parseTupleFmt; });

	out << boost::format("if(!PyArg_ParseTupleAndKeywords(args, kw, \"%s\", (char **)kwlist%s))\n"
	                     "    return 0;\n") % cat(formatStream) % cat(argStream);

}

void Function::codegenDefinitionBody(std::ostream &out) const
{
	// emit "try" block
	out << "try\n{\n";
	{
		IndentingOStreambuf indenter2(out);
		// call function
		{
			if(_lineNo >= 0)
				out << boost::format("#line %1% %2%\n") % _lineNo % std::quoted(_origFile);

			if(_returnType != "void")
			{
				out << _returnType << " result = ";
			}

			codegenCall(out);
		}

		if(_returnType != "void")
		{
			out << "return PyConversion<" << _returnType << ">::dump(result);\n";
		}
		else
		{
			out << "return Py_None;\n";
		}
	}
	out << "}\n";
	out << "catch(python::Exception &)\n{\n";
	out << "    return 0;\n";
	out << "}\n";
	out << "catch(std::exception &exc)\n{\n";
	// emit catch block
	{
		IndentingOStreambuf indenter2(out);
		out << "return PyErr_Format(PyExc_RuntimeError, \"%s\", exc.what());\n";
	}

	out << "}\n";
}
void Function::codegenDefinition(std::ostream &out) const
{
	using namespace streams;
	out << boost::format(FunctionPrototype) % _implName % selfTypeName() << "\n{\n";

	{
		IndentingOStreambuf indenter(out);
		codegenTupleUnpack(out);
		codegenDefinitionBody(out);
	}

	out << "}\n";
}

void Function::codegenMethodTable(std::ostream &out) const
{
	auto docstring = processDocString(_docstring);

	out << boost::format("{\"%1%\", (PyCFunction) %2%, METH_VARARGS|METH_KEYWORDS, %3%},\n")
		% pythonName()
		% implName()
		% ("\"" + docstring + "\"");
}
}  // namespace autobind

<commit_msg>Return Py_None correctly so that it doesn't get deallocated.<commit_after>#include <iomanip>
#include <boost/format.hpp>

#include "prefix.hpp"
#include "util.hpp"
#include "stream.hpp"
#include "streamindent.hpp"
#include "printing.hpp"
#include "Function.hpp"

#include <regex>

namespace autobind {

namespace
{
	const boost::format FunctionPrototype{
		"static PyObject *%s(%s *self, PyObject *args, PyObject *kw)"
	};

}

std::string processDocString(const std::string &docstring)
{
	auto result = std::regex_replace(docstring, std::regex("(^|\n)\\s*(///|\\*)"), "$1");
	replace(result, "\\", "\\\\");
	replace(result, "\n", "\\n");
	replace(result, "\"", "\\\"");

	return result;
}

Function::Function(std::string name, std::vector<Arg> args,
                   std::string docstring)
: Export(std::move(name))
, _args(std::move(args))
, _docstring(std::move(docstring))
{
	auto parts = rsplit(this->name(), "::");
	_unqualifiedName = parts.second;
	_implName = this->name();
	replace(_implName, "::", "_ns_");
	_implName += "_py_bind_impl";

}

void Function::codegenCall(std::ostream &out) const
{
	out << name();
	codegenCallArgs(out);
	out << ";\n";
}

void Function::codegenCallArgs(std::ostream &out) const
{

	using namespace streams;

	auto argStream = stream(_args)
		| enumerated()
		| pairTransformed([](int i, const Arg &a) {
			return a.requiresAdditionalConversion?
				  str(boost::format("PyConversion<%1%>::load(arg%2%)") % a.cppQualTypeName % i)
				: str(boost::format("arg%1%") % i);
		})
		| interposed(", ");

	out << "(" << cat(argStream) << ")";
}

void Function::codegenDeclaration(std::ostream &out) const
{
	out << boost::format(FunctionPrototype) % _implName % selfTypeName() << ";\n";
}

void Function::codegenTupleUnpack(std::ostream &out) const
{
	using namespace streams;
	// declare variables
	for(const auto &pair : stream(_args) | enumerated())
	{
		if(pair.second.requiresAdditionalConversion)
		{
			out << "PyObject *";
		}
		else
		{
			out << pair.second.cppQualTypeName << " ";
		}

		out << "arg" << pair.first << ";\n";
	}

	// call PyArg_ParseTuple
	auto kwlistStream = stream(_args)
		| transformed([](const Arg &a) { return "\"" + a.argName + "\", "; });

	out << boost::format("static const char *kwlist[] = {%1%0};\n") % cat(kwlistStream);

	auto argStream = count()
		| take(_args.size())
		| transformed([](int i) { return boost::format(", &arg%d") % i; });

	auto formatStream = stream(_args)
		| transformed([](const Arg &a) { return a.parseTupleFmt; });

	out << boost::format("if(!PyArg_ParseTupleAndKeywords(args, kw, \"%s\", (char **)kwlist%s))\n"
	                     "    return 0;\n") % cat(formatStream) % cat(argStream);

}

void Function::codegenDefinitionBody(std::ostream &out) const
{
	// emit "try" block
	out << "try\n{\n";
	{
		IndentingOStreambuf indenter2(out);
		// call function
		{
			if(_lineNo >= 0)
				out << boost::format("#line %1% %2%\n") % _lineNo % std::quoted(_origFile);

			if(_returnType != "void")
			{
				out << _returnType << " result = ";
			}

			codegenCall(out);
		}

		if(_returnType != "void")
		{
			out << "return PyConversion<" << _returnType << ">::dump(result);\n";
		}
		else
		{
			out << "Py_RETURN_NONE;\n";
		}
	}
	out << "}\n";
	out << "catch(python::Exception &)\n{\n";
	out << "    return 0;\n";
	out << "}\n";
	out << "catch(std::exception &exc)\n{\n";
	// emit catch block
	{
		IndentingOStreambuf indenter2(out);
		out << "return PyErr_Format(PyExc_RuntimeError, \"%s\", exc.what());\n";
	}

	out << "}\n";
}
void Function::codegenDefinition(std::ostream &out) const
{
	using namespace streams;
	out << boost::format(FunctionPrototype) % _implName % selfTypeName() << "\n{\n";

	{
		IndentingOStreambuf indenter(out);
		codegenTupleUnpack(out);
		codegenDefinitionBody(out);
	}

	out << "}\n";
}

void Function::codegenMethodTable(std::ostream &out) const
{
	auto docstring = processDocString(_docstring);

	out << boost::format("{\"%1%\", (PyCFunction) %2%, METH_VARARGS|METH_KEYWORDS, %3%},\n")
		% pythonName()
		% implName()
		% ("\"" + docstring + "\"");
}
}  // namespace autobind

<|endoftext|>


<commit_before>#ifndef QUANT_PDE_FUNCTION_HPP
#define QUANT_PDE_FUNCTION_HPP

#include <cstring> // std::memcpy

namespace QuantPDE {

/**
 * Represents a function \f$f\f$ defined on some domain.
 */
class Function {

	virtual Real get(const Real *) const = 0;

public:

	/**
	 * @param coordinates Coordinates \f$\left\{c_i\right\}\f$ (passed in
	 *                    as an array) specifying a point in \f$f\f$'s
	 *                    domain.
	 * @return The value of \f$f\f$ at the specified coordinates (i.e.
	 *         \f$f\left(c_0, \ldots, c_{n-1}\right)\f$).
	 */
	Real operator()(const Real *coordinates) const {
		return get(coordinates);
	}

	/**
	 * @param coordinates Coordinates \f$\left\{c_i\right\}\f$ specifying
	 *                    a point in \f$f\f$'s domain.
	 * @return The value of \f$f\f$ at the specified coordinates (i.e.
	 *         \f$f\left(c_0, \ldots, c_{n-1}\right)\f$).
	 */
	template <typename ...ArgsT>
	Real operator()(ArgsT ...coordinates) const {
		Real coords[] {coordinates...};
		return get(coords);
	}

	/**
	 * @param grid A grid.
	 * @return The image of this function on the set of grid nodes as a
	 *         vector.
	 */
	virtual Vector image(const Grid &grid) const {
		Vector v = grid.vector();

		Real *coordinates = new Real[grid.size()];
		for(auto node : grid.accessor(v)) {
			grid.coordinates(&node, coordinates);
			*node = get(coordinates);
		}
		delete [] coordinates;

		return v;
	}

};

/**
 * Represents a function defined on a one-dimensional domain.
 */
class Function1d : public Function {

	virtual Real get(const Real *coordinates) const {
		return get(*coordinates);
	}

	virtual Real get(Real) const = 0;

public:

	virtual Vector image(const Grid &grid) const {
		Vector v = grid.vector();

		Real coordinates[1];
		for(auto node : grid.accessor(v)) {
			grid.coordinates(&node, coordinates);
			*node = get(*coordinates);
		}

		return v;
	}

};

// TODO: Function2d, Function3d, Function4d

/**
 * A function \f$f\f$ whose value is constant (i.e. \f$f\left(x\right)=c\f$ for
 * all \f$x\f$ in the domain of \f$f\f$).
 */
class Constant : public Function {

	Real c;

	virtual Real get(const Real *coordinates) const {
		return c;
	}

public:

	/**
	 * Constructor.
	 * @param c The value of the function everywhere.
	 */
	Constant(Real c) : c(c) {
	}

	/**
	 * Copy constructor.
	 */
	Constant(const Constant &that) : c(that.c) {
	}

};

/**
 * A function \f$f\f$ defined piecewise whose pieces are affine functions.
 * Suppose \f$f\f$ is defined on a grid composed of \f$n\f$ axes, and that the
 * \f$i\f$-th axis is a partition consisting of \f$m_i\f$ nodes.
 * Querying \f$f\f$ at a point involves a binary search on each axis.
 * This procedure has worst-case complexity
 * \f$\sim \sum_i \lg m_i \leq n \lg m\f$, where
 * \f$m \equiv \max\left\{m_i\right\}\f$.
 */
class PiecewiseLinear : public Function {

	const Grid &grid;
	const Vector &vector;

	Real interpolate(const Index *indices, const Real *start,
			const Real *end) const {
		if(start == end) {
			return grid.accessor(vector)(indices);
		}

		Index dim = grid.size();
		Index *other = new Index[dim];
		std::memcpy(other, indices, sizeof(Index) * dim);
		other[dim - (end - start)]++;

		Real v = (*start)
				* interpolate(indices, start + 1, end)
				+ (1 - *start) * interpolate(other, start + 1,
				end);

		delete [] other;

		return v;
	}

	virtual Real get(const Real *coordinates) const {
		Index dim = grid.size();

		Index *indices = new Index[dim];
		Real *weights = new Real[dim];

		{
			for(Index i = 0; i < grid.size(); i++, coordinates++) {
				const Axis &x = grid(i);
				Index length = x.size();

				if(*coordinates <= x(0)) {
					indices[i] = 0;
					weights[i] = 1.;
					continue;
				}

				if(*coordinates >= x(length - 1)) {
					indices[i] = length - 2;
					weights[i] = 0.;
					continue;
				}

				// Binary search to find node
				Index lo = 0, hi = length - 2, mid = 0;
				Real weight = 0.;
				while(lo <= hi) {
					mid = (lo + hi) / 2;
					if(*coordinates < x(mid)) {
						hi = mid - 1;
					} else if(*coordinates >= x(mid + 1)) {
						lo = mid + 1;
					} else {
						weight = (x(mid + 1)
								- *coordinates)
								/ ( x(mid + 1)
								- x(mid) );
						break;
					}
				}

				indices[i] = mid;
				weights[i] = weight;
			}
		}

		Real v = interpolate(indices, weights, weights + dim);

		delete [] indices;
		delete [] weights;

		return v;
	}

public:

	/**
	 * Constructor.
	 * @param grid A grid.
	 * @param vector A vector containing the values of the function at the
	 *               grid nodes.
	 */
	PiecewiseLinear(const Grid &grid, const Vector &vector) : grid(grid),
			vector(vector) {
	}

	/**
	 * Copy constructor.
	 */
	PiecewiseLinear(const PiecewiseLinear &that) : grid(that.grid),
			vector(that.vector) {
	}

};

template <bool isConst>
Real Grid::GridVector<isConst>::operator()(const Real *coordinates) const {
	return (PiecewiseLinear(grid, vector))(coordinates);
}

}

#endif

<commit_msg>Memory is initialized only once per linear interpolation in arbitrary dimensions.<commit_after>#ifndef QUANT_PDE_FUNCTION_HPP
#define QUANT_PDE_FUNCTION_HPP

#include <cstring> // std::memcpy

namespace QuantPDE {

/**
 * Represents a function \f$f\f$ defined on some domain.
 */
class Function {

	virtual Real get(const Real *) const = 0;

public:

	/**
	 * @param coordinates Coordinates \f$\left\{c_i\right\}\f$ (passed in
	 *                    as an array) specifying a point in \f$f\f$'s
	 *                    domain.
	 * @return The value of \f$f\f$ at the specified coordinates (i.e.
	 *         \f$f\left(c_0, \ldots, c_{n-1}\right)\f$).
	 */
	Real operator()(const Real *coordinates) const {
		return get(coordinates);
	}

	/**
	 * @param coordinates Coordinates \f$\left\{c_i\right\}\f$ specifying
	 *                    a point in \f$f\f$'s domain.
	 * @return The value of \f$f\f$ at the specified coordinates (i.e.
	 *         \f$f\left(c_0, \ldots, c_{n-1}\right)\f$).
	 */
	template <typename ...ArgsT>
	Real operator()(ArgsT ...coordinates) const {
		Real coords[] {coordinates...};
		return get(coords);
	}

	/**
	 * @param grid A grid.
	 * @return The image of this function on the set of grid nodes as a
	 *         vector.
	 */
	virtual Vector image(const Grid &grid) const {
		Vector v = grid.vector();

		Real *coordinates = new Real[grid.size()];
		for(auto node : grid.accessor(v)) {
			grid.coordinates(&node, coordinates);
			*node = get(coordinates);
		}
		delete [] coordinates;

		return v;
	}

};

/**
 * Represents a function defined on a one-dimensional domain.
 */
class Function1d : public Function {

	virtual Real get(const Real *coordinates) const {
		return get(*coordinates);
	}

	virtual Real get(Real) const = 0;

public:

	virtual Vector image(const Grid &grid) const {
		Vector v = grid.vector();

		Real coordinates[1];
		for(auto node : grid.accessor(v)) {
			grid.coordinates(&node, coordinates);
			*node = get(*coordinates);
		}

		return v;
	}

};

// TODO: Function2d, Function3d, Function4d

/**
 * A function \f$f\f$ whose value is constant (i.e. \f$f\left(x\right)=c\f$ for
 * all \f$x\f$ in the domain of \f$f\f$).
 */
class Constant : public Function {

	Real c;

	virtual Real get(const Real *coordinates) const {
		return c;
	}

public:

	/**
	 * Constructor.
	 * @param c The value of the function everywhere.
	 */
	Constant(Real c) : c(c) {
	}

	/**
	 * Copy constructor.
	 */
	Constant(const Constant &that) : c(that.c) {
	}

};

/**
 * A function \f$f\f$ defined piecewise whose pieces are affine functions.
 * Suppose \f$f\f$ is defined on a grid composed of \f$n\f$ axes, and that the
 * \f$i\f$-th axis is a partition consisting of \f$m_i\f$ nodes.
 * Querying \f$f\f$ at a point involves a binary search on each axis.
 * This procedure has worst-case complexity
 * \f$\sim \sum_i \lg m_i \leq n \lg m\f$, where
 * \f$m \equiv \max\left\{m_i\right\}\f$.
 */
class PiecewiseLinear : public Function {

	const Grid &grid;
	const Vector &vector;

	Real interpolate(Index *indices, Real *weights, Index n = 0) const {
		const Index dim = grid.size();

		// Base case
		if(n == dim) {
			return grid.accessor(vector)(indices);
		}

		Index *stride = indices + ( (dim - n) * dim );
		std::memcpy(stride, indices, sizeof(Index) * dim);
		stride[dim - n]++;

		return weights[n] * interpolate(indices, weights, n + 1)
				+ (1 - weights[n]) * interpolate(stride,
				weights, n + 1);
	}

	virtual Real get(const Real *coordinates) const {
		const Index dim = grid.size();

		Real *weights = new Real[dim];

		// We need 2^dim arrays of size dim to store indices for the
		// interpolation routine. Initialize all of this at once.
		Index *indices;
		{
			Index power = 1;
			for(Index i = 0; i < dim; i++) {
				power *= 2;
			}

			indices = new Index[power * dim];
		}

		// For the i-th coordinate, find the ticks on the i-th axis that
		// it lies between along with the distance from the leftmost
		// tick
		for(Index i = 0; i < dim; i++, coordinates++) {
			const Axis &x = grid(i);
			Index length = x.size();

			if(*coordinates <= x(0)) {
				indices[i] = 0;
				weights[i] = 1.;
				continue;
			}

			if(*coordinates >= x(length - 1)) {
				indices[i] = length - 2;
				weights[i] = 0.;
				continue;
			}

			// Binary search to find tick
			Index lo = 0, hi = length - 2, mid = 0;
			Real weight = 0.;
			while(lo <= hi) {
				mid = (lo + hi) / 2;
				if(*coordinates < x(mid)) {
					hi = mid - 1;
				} else if(*coordinates >= x(mid + 1)) {
					lo = mid + 1;
				} else {
					weight = (x(mid + 1)
							- *coordinates)
							/ ( x(mid + 1)
							- x(mid) );
					break;
				}
			}

			indices[i] = mid;
			weights[i] = weight;
		}

		const Real v = interpolate(indices, weights);

		delete [] indices;
		delete [] weights;

		return v;
	}

public:

	/**
	 * Constructor.
	 * @param grid A grid.
	 * @param vector A vector containing the values of the function at the
	 *               grid nodes.
	 */
	PiecewiseLinear(const Grid &grid, const Vector &vector) : grid(grid),
			vector(vector) {
	}

	/**
	 * Copy constructor.
	 */
	PiecewiseLinear(const PiecewiseLinear &that) : grid(that.grid),
			vector(that.vector) {
	}

};

template <bool isConst>
Real Grid::GridVector<isConst>::operator()(const Real *coordinates) const {
	return (PiecewiseLinear(grid, vector))(coordinates);
}

}

#endif

<|endoftext|>


<commit_before>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#include "InternalVolumetricFlowRate.h"
#include "FVUtils.h"
#include <math.h>

registerMooseObject("NavierStokesApp", InternalVolumetricFlowRate);

InputParameters
InternalVolumetricFlowRate::validParams()
{
  InputParameters params = InterfaceIntegralPostprocessor::validParams();
  params.addClassDescription(
      "Computes the volumetric flow rate of an advected quantity through an internal boundary.");
  params.addParam<bool>("fv", false, "Whether finite volume variables are used");
  params.addRequiredCoupledVar("vel_x", "The x-axis velocity");
  params.addCoupledVar("vel_y", 0, "The y-axis velocity");
  params.addCoupledVar("vel_z", 0, "The z-axis velocity");
  MooseEnum advected_interp_method("average upwind", "upwind");
  params.addParam<MooseEnum>("advected_interp_method",
                             advected_interp_method,
                             "The interpolation to use for the advected quantity. Options are "
                             "'upwind' and 'average', with the default being 'upwind'.");
  params.addCoupledVar(
      "advected_variable", 0, "The advected variable quantity of which to study the flow");
  params.addParam<MaterialPropertyName>(
      "advected_mat_prop", 0, "The advected material property of which to study the flow");
  return params;
}

InternalVolumetricFlowRate::InternalVolumetricFlowRate(const InputParameters & parameters)
  : InterfaceIntegralPostprocessor(parameters),
    _fv(getParam<bool>("fv")),
    _vel_x(coupledValue("vel_x")),
    _vel_y(coupledValue("vel_y")),
    _vel_z(coupledValue("vel_z")),
    _fv_vel_x(dynamic_cast<const MooseVariableFV<Real> *>(getFieldVar("vel_x", 0))),
    _fv_vel_y(dynamic_cast<const MooseVariableFV<Real> *>(getFieldVar("vel_y", 0))),
    _fv_vel_z(dynamic_cast<const MooseVariableFV<Real> *>(getFieldVar("vel_z", 0))),
    _advected_variable_supplied(parameters.isParamSetByUser("advected_variable")),
    _advected_variable(coupledValue("advected_variable")),
    _fv_advected_variable(
        dynamic_cast<const MooseVariableFV<Real> *>(getFieldVar("advected_variable", 0))),
    _advected_mat_prop_supplied(parameters.isParamSetByUser("advected_mat_prop")),
    _advected_material_property(getADMaterialProperty<Real>("advected_mat_prop")),
    _advected_material_property_neighbor(getNeighborADMaterialProperty<Real>("advected_mat_prop"))
{
  // Check that at most one advected quantity has been provided
  if (_advected_variable_supplied && _advected_mat_prop_supplied)
    mooseError(
        "InternalVolumetricFlowRatePostprocessor should be provided either an advected variable or "
        "an advected material property");

  using namespace Moose::FV;

  const auto & advected_interp_method = getParam<MooseEnum>("advected_interp_method");
  if (advected_interp_method == "average")
    _advected_interp_method = InterpMethod::Average;
  else if (advected_interp_method == "upwind")
    _advected_interp_method = InterpMethod::Upwind;
  else
    mooseError("Unrecognized advected quantity interpolation type ",
               static_cast<std::string>(advected_interp_method));
}

Real
InternalVolumetricFlowRate::computeQpIntegral()
{
#ifdef MOOSE_GLOBAL_AD_INDEXING
  if (_fv)
  {
    // We should not be at a boundary
    const FaceInfo * const fi = _mesh.faceInfo(_current_elem, _current_side);
    mooseAssert(fi, "We should have a face info");
    mooseAssert(
        !fi->isBoundary(),
        "Use VolumetricFlowRate instead of InternalVolumetricFlowRate for domain boundaries");

    const Elem * const neighbor = _current_elem->neighbor_ptr(_current_side);

    // Get face value for velocity
    // FIXME Make sure getInternalFaceValue uses the right interpolation method, see #16585
    const auto & vx_face =
        _fv_vel_x
            ? MetaPhysicL::raw_value(_fv_vel_x->getInternalFaceValue(neighbor, *fi, _vel_x[_qp]))
            : _vel_x[_qp];

    const auto & vy_face =
        _fv_vel_y
            ? MetaPhysicL::raw_value(_fv_vel_y->getInternalFaceValue(neighbor, *fi, _vel_y[_qp]))
            : _vel_y[_qp];

    const auto & vz_face =
        _fv_vel_z
            ? MetaPhysicL::raw_value(_fv_vel_z->getInternalFaceValue(neighbor, *fi, _vel_z[_qp]))
            : _vel_z[_qp];

    // Compute the advected quantity on the face
    Real advected_quantity;
    if (_advected_variable_supplied)
    {
      // Get neighbor value
      const auto & advected_variable_neighbor =
          _fv_advected_variable ? MetaPhysicL::raw_value(_fv_advected_variable->getNeighborValue(
                                      neighbor, *fi, _advected_variable[_qp]))
                                : _advected_variable[_qp];

      Moose::FV::interpolate(_advected_interp_method,
                             advected_quantity,
                             MetaPhysicL::raw_value(_advected_variable[_qp]),
                             MetaPhysicL::raw_value(advected_variable_neighbor),
                             RealVectorValue(vx_face, vy_face, vz_face),
                             *fi,
                             true);
    }
    else if (_advected_mat_prop_supplied)
    {
      // The material property needs to be interpolated since we are on an internal face
      Moose::FV::interpolate(_advected_interp_method,
                             advected_quantity,
                             MetaPhysicL::raw_value(_advected_material_property[_qp]),
                             MetaPhysicL::raw_value(_advected_material_property_neighbor[_qp]),
                             RealVectorValue(vx_face, vy_face, vz_face),
                             *fi,
                             true);
    }
    else
      advected_quantity = 1;

    return advected_quantity * RealVectorValue(vx_face, vy_face, vz_face) * _normals[_qp];
  }
  else
#endif
  {
    if (parameters().isParamSetByUser("advected_variable"))
      return _advected_variable[_qp] * RealVectorValue(_vel_x[_qp], _vel_y[_qp], _vel_z[_qp]) *
             _normals[_qp];
    else if (parameters().isParamSetByUser("advected_mat_prop"))
      return MetaPhysicL::raw_value(_advected_material_property[_qp]) *
             RealVectorValue(_vel_x[_qp], _vel_y[_qp], _vel_z[_qp]) * _normals[_qp];
    else
      return RealVectorValue(_vel_x[_qp], _vel_y[_qp], _vel_z[_qp]) * _normals[_qp];
  }
}
<commit_msg>Pass current_elem_is_fi_elem to Moose::FV::interpolate<commit_after>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#include "InternalVolumetricFlowRate.h"
#include "FVUtils.h"
#include <math.h>

registerMooseObject("NavierStokesApp", InternalVolumetricFlowRate);

InputParameters
InternalVolumetricFlowRate::validParams()
{
  InputParameters params = InterfaceIntegralPostprocessor::validParams();
  params.addClassDescription(
      "Computes the volumetric flow rate of an advected quantity through an internal boundary.");
  params.addParam<bool>("fv", false, "Whether finite volume variables are used");
  params.addRequiredCoupledVar("vel_x", "The x-axis velocity");
  params.addCoupledVar("vel_y", 0, "The y-axis velocity");
  params.addCoupledVar("vel_z", 0, "The z-axis velocity");
  MooseEnum advected_interp_method("average upwind", "upwind");
  params.addParam<MooseEnum>("advected_interp_method",
                             advected_interp_method,
                             "The interpolation to use for the advected quantity. Options are "
                             "'upwind' and 'average', with the default being 'upwind'.");
  params.addCoupledVar(
      "advected_variable", 0, "The advected variable quantity of which to study the flow");
  params.addParam<MaterialPropertyName>(
      "advected_mat_prop", 0, "The advected material property of which to study the flow");
  return params;
}

InternalVolumetricFlowRate::InternalVolumetricFlowRate(const InputParameters & parameters)
  : InterfaceIntegralPostprocessor(parameters),
    _fv(getParam<bool>("fv")),
    _vel_x(coupledValue("vel_x")),
    _vel_y(coupledValue("vel_y")),
    _vel_z(coupledValue("vel_z")),
    _fv_vel_x(dynamic_cast<const MooseVariableFV<Real> *>(getFieldVar("vel_x", 0))),
    _fv_vel_y(dynamic_cast<const MooseVariableFV<Real> *>(getFieldVar("vel_y", 0))),
    _fv_vel_z(dynamic_cast<const MooseVariableFV<Real> *>(getFieldVar("vel_z", 0))),
    _advected_variable_supplied(parameters.isParamSetByUser("advected_variable")),
    _advected_variable(coupledValue("advected_variable")),
    _fv_advected_variable(
        dynamic_cast<const MooseVariableFV<Real> *>(getFieldVar("advected_variable", 0))),
    _advected_mat_prop_supplied(parameters.isParamSetByUser("advected_mat_prop")),
    _advected_material_property(getADMaterialProperty<Real>("advected_mat_prop")),
    _advected_material_property_neighbor(getNeighborADMaterialProperty<Real>("advected_mat_prop"))
{
  // Check that at most one advected quantity has been provided
  if (_advected_variable_supplied && _advected_mat_prop_supplied)
    mooseError(
        "InternalVolumetricFlowRatePostprocessor should be provided either an advected variable or "
        "an advected material property");

  using namespace Moose::FV;

  const auto & advected_interp_method = getParam<MooseEnum>("advected_interp_method");
  if (advected_interp_method == "average")
    _advected_interp_method = InterpMethod::Average;
  else if (advected_interp_method == "upwind")
    _advected_interp_method = InterpMethod::Upwind;
  else
    mooseError("Unrecognized advected quantity interpolation type ",
               static_cast<std::string>(advected_interp_method));
}

Real
InternalVolumetricFlowRate::computeQpIntegral()
{
#ifdef MOOSE_GLOBAL_AD_INDEXING
  if (_fv)
  {
    // We should not be at a boundary
    const FaceInfo * const fi = _mesh.faceInfo(_current_elem, _current_side);
    mooseAssert(fi, "We should have a face info");
    mooseAssert(
        !fi->isBoundary(),
        "Use VolumetricFlowRate instead of InternalVolumetricFlowRate for domain boundaries");
    const bool current_elem_is_fi_elem = (_current_elem == &fi->elem());

    const Elem * const neighbor = _current_elem->neighbor_ptr(_current_side);

    // Get face value for velocity
    // FIXME Make sure getInternalFaceValue uses the right interpolation method, see #16585
    const auto & vx_face =
        _fv_vel_x
            ? MetaPhysicL::raw_value(_fv_vel_x->getInternalFaceValue(neighbor, *fi, _vel_x[_qp]))
            : _vel_x[_qp];

    const auto & vy_face =
        _fv_vel_y
            ? MetaPhysicL::raw_value(_fv_vel_y->getInternalFaceValue(neighbor, *fi, _vel_y[_qp]))
            : _vel_y[_qp];

    const auto & vz_face =
        _fv_vel_z
            ? MetaPhysicL::raw_value(_fv_vel_z->getInternalFaceValue(neighbor, *fi, _vel_z[_qp]))
            : _vel_z[_qp];

    // Compute the advected quantity on the face
    Real advected_quantity;
    if (_advected_variable_supplied)
    {
      // Get neighbor value
      const auto & advected_variable_neighbor =
          _fv_advected_variable ? MetaPhysicL::raw_value(_fv_advected_variable->getNeighborValue(
                                      neighbor, *fi, _advected_variable[_qp]))
                                : _advected_variable[_qp];

      Moose::FV::interpolate(_advected_interp_method,
                             advected_quantity,
                             MetaPhysicL::raw_value(_advected_variable[_qp]),
                             MetaPhysicL::raw_value(advected_variable_neighbor),
                             RealVectorValue(vx_face, vy_face, vz_face),
                             *fi,
                             current_elem_is_fi_elem);
    }
    else if (_advected_mat_prop_supplied)
    {
      // The material property needs to be interpolated since we are on an internal face
      Moose::FV::interpolate(_advected_interp_method,
                             advected_quantity,
                             MetaPhysicL::raw_value(_advected_material_property[_qp]),
                             MetaPhysicL::raw_value(_advected_material_property_neighbor[_qp]),
                             RealVectorValue(vx_face, vy_face, vz_face),
                             *fi,
                             current_elem_is_fi_elem);
    }
    else
      advected_quantity = 1;

    return advected_quantity * RealVectorValue(vx_face, vy_face, vz_face) * _normals[_qp];
  }
  else
#endif
  {
    if (parameters().isParamSetByUser("advected_variable"))
      return _advected_variable[_qp] * RealVectorValue(_vel_x[_qp], _vel_y[_qp], _vel_z[_qp]) *
             _normals[_qp];
    else if (parameters().isParamSetByUser("advected_mat_prop"))
      return MetaPhysicL::raw_value(_advected_material_property[_qp]) *
             RealVectorValue(_vel_x[_qp], _vel_y[_qp], _vel_z[_qp]) * _normals[_qp];
    else
      return RealVectorValue(_vel_x[_qp], _vel_y[_qp], _vel_z[_qp]) * _normals[_qp];
  }
}
<|endoftext|>


<commit_before>/*********************************************************************
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2012, Willow Garage, Inc.
 *  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.
 *   * Neither the name of Willow Garage nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  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 OWNER 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.
 *********************************************************************/

/* Author: Ioan Sucan */

#include <moveit/planning_request_adapter/planning_request_adapter.h>
#include <functional>
#include <algorithm>

namespace planning_request_adapter
{
namespace
{
bool callPlannerInterfaceSolve(const planning_interface::PlannerManager& planner,
                               const planning_scene::PlanningSceneConstPtr& planning_scene,
                               const planning_interface::MotionPlanRequest& req,
                               planning_interface::MotionPlanResponse& res)
{
  planning_interface::PlanningContextPtr context = planner.getPlanningContext(planning_scene, req, res.error_code_);
  if (context)
    return context->solve(res);
  else
    return false;
}

bool callAdapter(const PlanningRequestAdapter& adapter, const PlanningRequestAdapter::PlannerFn& planner,
                 const planning_scene::PlanningSceneConstPtr& planning_scene,
                 const planning_interface::MotionPlanRequest& req, planning_interface::MotionPlanResponse& res,
                 std::vector<std::size_t>& added_path_index)
{
  try
  {
    bool result = adapter.adaptAndPlan(planner, planning_scene, req, res, added_path_index);
    ROS_DEBUG_STREAM_NAMED("planning_request_adapter", adapter.getDescription() << ": " << res.error_code_.val);
    return result;
  }
  catch (std::exception& ex)
  {
    ROS_ERROR_NAMED("planning_request_adapter",
                    "Exception caught executing adapter '%s': %s\nSkipping adapter instead.",
                    adapter.getDescription().c_str(), ex.what());
    added_path_index.clear();
    return planner(planning_scene, req, res);
  }
}

}  // namespace

bool PlanningRequestAdapter::adaptAndPlan(const planning_interface::PlannerManagerPtr& planner,
                                          const planning_scene::PlanningSceneConstPtr& planning_scene,
                                          const planning_interface::MotionPlanRequest& req,
                                          planning_interface::MotionPlanResponse& res,
                                          std::vector<std::size_t>& added_path_index) const
{
  return adaptAndPlan(
      [&planner](const planning_scene::PlanningSceneConstPtr& scene, const planning_interface::MotionPlanRequest& req,
                 planning_interface::MotionPlanResponse& res) {
        return callPlannerInterfaceSolve(*planner, scene, req, res);
      },
      planning_scene, req, res, added_path_index);
}

bool PlanningRequestAdapter::adaptAndPlan(const planning_interface::PlannerManagerPtr& planner,
                                          const planning_scene::PlanningSceneConstPtr& planning_scene,
                                          const planning_interface::MotionPlanRequest& req,
                                          planning_interface::MotionPlanResponse& res) const
{
  std::vector<std::size_t> dummy;
  return adaptAndPlan(planner, planning_scene, req, res, dummy);
}

bool PlanningRequestAdapterChain::adaptAndPlan(const planning_interface::PlannerManagerPtr& planner,
                                               const planning_scene::PlanningSceneConstPtr& planning_scene,
                                               const planning_interface::MotionPlanRequest& req,
                                               planning_interface::MotionPlanResponse& res) const
{
  std::vector<std::size_t> dummy;
  return adaptAndPlan(planner, planning_scene, req, res, dummy);
}

bool PlanningRequestAdapterChain::adaptAndPlan(const planning_interface::PlannerManagerPtr& planner,
                                               const planning_scene::PlanningSceneConstPtr& planning_scene,
                                               const planning_interface::MotionPlanRequest& req,
                                               planning_interface::MotionPlanResponse& res,
                                               std::vector<std::size_t>& added_path_index) const
{
  // if there are no adapters, run the planner directly
  if (adapters_.empty())
  {
    added_path_index.clear();
    return callPlannerInterfaceSolve(*planner, planning_scene, req, res);
  }
  else
  {
    // the index values added by each adapter
    std::vector<std::vector<std::size_t> > added_path_index_each(adapters_.size());

    // if there are adapters, construct a function for each, in order,
    // so that in the end we have a nested sequence of functions that calls all adapters
    // and eventually the planner in the correct order.
    PlanningRequestAdapter::PlannerFn fn = [&planner = *planner](const planning_scene::PlanningSceneConstPtr& scene,
                                                                 const planning_interface::MotionPlanRequest& req,
                                                                 planning_interface::MotionPlanResponse& res) {
      return callPlannerInterfaceSolve(planner, scene, req, res);
    };

    for (int i = adapters_.size() - 1; i >= 0; --i)
    {
      fn = [&adapter = *adapters_[i], fn, &added_path_index = added_path_index_each[i]](
               const planning_scene::PlanningSceneConstPtr& scene, const planning_interface::MotionPlanRequest& req,
               planning_interface::MotionPlanResponse& res) {
        return callAdapter(adapter, fn, scene, req, res, added_path_index);
      };
    }

    bool result = fn(planning_scene, req, res);
    added_path_index.clear();

    // merge the index values from each adapter
    for (std::vector<std::size_t>& added_states_by_each_adapter : added_path_index_each)
      for (std::size_t& added_index : added_states_by_each_adapter)
      {
        for (std::size_t& index_in_path : added_path_index)
          if (added_index <= index_in_path)
            index_in_path++;
        added_path_index.push_back(added_index);
      }
    std::sort(added_path_index.begin(), added_path_index.end());
    return result;
  }
}

}  // end of namespace planning_request_adapter
<commit_msg>Further improve debug message using new operator<<(MoveItErrorCode)<commit_after>/*********************************************************************
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2012, Willow Garage, Inc.
 *  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.
 *   * Neither the name of Willow Garage nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  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 OWNER 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.
 *********************************************************************/

/* Author: Ioan Sucan */

#include <moveit/utils/moveit_error_code.h>
#include <moveit/planning_request_adapter/planning_request_adapter.h>
#include <functional>
#include <algorithm>

namespace planning_request_adapter
{
namespace
{
bool callPlannerInterfaceSolve(const planning_interface::PlannerManager& planner,
                               const planning_scene::PlanningSceneConstPtr& planning_scene,
                               const planning_interface::MotionPlanRequest& req,
                               planning_interface::MotionPlanResponse& res)
{
  planning_interface::PlanningContextPtr context = planner.getPlanningContext(planning_scene, req, res.error_code_);
  if (context)
    return context->solve(res);
  else
    return false;
}

bool callAdapter(const PlanningRequestAdapter& adapter, const PlanningRequestAdapter::PlannerFn& planner,
                 const planning_scene::PlanningSceneConstPtr& planning_scene,
                 const planning_interface::MotionPlanRequest& req, planning_interface::MotionPlanResponse& res,
                 std::vector<std::size_t>& added_path_index)
{
  try
  {
    bool result = adapter.adaptAndPlan(planner, planning_scene, req, res, added_path_index);
    ROS_DEBUG_STREAM_NAMED("planning_request_adapter", adapter.getDescription()
                                                           << ": " << moveit::core::MoveItErrorCode(res.error_code_));
    return result;
  }
  catch (std::exception& ex)
  {
    ROS_ERROR_NAMED("planning_request_adapter",
                    "Exception caught executing adapter '%s': %s\nSkipping adapter instead.",
                    adapter.getDescription().c_str(), ex.what());
    added_path_index.clear();
    return planner(planning_scene, req, res);
  }
}

}  // namespace

bool PlanningRequestAdapter::adaptAndPlan(const planning_interface::PlannerManagerPtr& planner,
                                          const planning_scene::PlanningSceneConstPtr& planning_scene,
                                          const planning_interface::MotionPlanRequest& req,
                                          planning_interface::MotionPlanResponse& res,
                                          std::vector<std::size_t>& added_path_index) const
{
  return adaptAndPlan(
      [&planner](const planning_scene::PlanningSceneConstPtr& scene, const planning_interface::MotionPlanRequest& req,
                 planning_interface::MotionPlanResponse& res) {
        return callPlannerInterfaceSolve(*planner, scene, req, res);
      },
      planning_scene, req, res, added_path_index);
}

bool PlanningRequestAdapter::adaptAndPlan(const planning_interface::PlannerManagerPtr& planner,
                                          const planning_scene::PlanningSceneConstPtr& planning_scene,
                                          const planning_interface::MotionPlanRequest& req,
                                          planning_interface::MotionPlanResponse& res) const
{
  std::vector<std::size_t> dummy;
  return adaptAndPlan(planner, planning_scene, req, res, dummy);
}

bool PlanningRequestAdapterChain::adaptAndPlan(const planning_interface::PlannerManagerPtr& planner,
                                               const planning_scene::PlanningSceneConstPtr& planning_scene,
                                               const planning_interface::MotionPlanRequest& req,
                                               planning_interface::MotionPlanResponse& res) const
{
  std::vector<std::size_t> dummy;
  return adaptAndPlan(planner, planning_scene, req, res, dummy);
}

bool PlanningRequestAdapterChain::adaptAndPlan(const planning_interface::PlannerManagerPtr& planner,
                                               const planning_scene::PlanningSceneConstPtr& planning_scene,
                                               const planning_interface::MotionPlanRequest& req,
                                               planning_interface::MotionPlanResponse& res,
                                               std::vector<std::size_t>& added_path_index) const
{
  // if there are no adapters, run the planner directly
  if (adapters_.empty())
  {
    added_path_index.clear();
    return callPlannerInterfaceSolve(*planner, planning_scene, req, res);
  }
  else
  {
    // the index values added by each adapter
    std::vector<std::vector<std::size_t> > added_path_index_each(adapters_.size());

    // if there are adapters, construct a function for each, in order,
    // so that in the end we have a nested sequence of functions that calls all adapters
    // and eventually the planner in the correct order.
    PlanningRequestAdapter::PlannerFn fn = [&planner = *planner](const planning_scene::PlanningSceneConstPtr& scene,
                                                                 const planning_interface::MotionPlanRequest& req,
                                                                 planning_interface::MotionPlanResponse& res) {
      return callPlannerInterfaceSolve(planner, scene, req, res);
    };

    for (int i = adapters_.size() - 1; i >= 0; --i)
    {
      fn = [&adapter = *adapters_[i], fn, &added_path_index = added_path_index_each[i]](
               const planning_scene::PlanningSceneConstPtr& scene, const planning_interface::MotionPlanRequest& req,
               planning_interface::MotionPlanResponse& res) {
        return callAdapter(adapter, fn, scene, req, res, added_path_index);
      };
    }

    bool result = fn(planning_scene, req, res);
    added_path_index.clear();

    // merge the index values from each adapter
    for (std::vector<std::size_t>& added_states_by_each_adapter : added_path_index_each)
      for (std::size_t& added_index : added_states_by_each_adapter)
      {
        for (std::size_t& index_in_path : added_path_index)
          if (added_index <= index_in_path)
            index_in_path++;
        added_path_index.push_back(added_index);
      }
    std::sort(added_path_index.begin(), added_path_index.end());
    return result;
  }
}

}  // end of namespace planning_request_adapter
<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright 2011-2013 The University of North Carolina at Chapel Hill
 *  All rights reserved.
 *
 *  Licensed under the MADAI Software License. You may obtain a copy of
 *  this license at
 *
 *         https://madai-public.cs.unc.edu/software/license/
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

#include "PercentileGridSampler.h"
#include "GaussianProcessEmulatedModel.h"
#include "RuntimeParameterFileReader.h"
#include "ApplicationUtilities.h"
#include "Paths.h"
#include "Trace.h"

#include "madaisys/SystemTools.hxx"

using madai::Model;
using madai::Paths;

const int DEFAULT_PERCENTILE_GRID_SAMPLES = 100;

template<class S, class T>
int findIndex(const S & v, const T & s)
{
  typename S::const_iterator it = std::find(v.begin(), v.end(), s);
  if (it == v.end())
    return -1;
  return std::distance(v.begin(), it);
}

/**
   Load a file with experimental observations in it.  The model will
   be comared against this. */
Model::ErrorType
LoadObservations(Model * model, std::istream & i)
{
  // std::ifstream i("DIRECTORY/experimental_results/results.dat");
  const std::vector< std::string > & scalarOutputNames = model->GetScalarOutputNames();
  unsigned int numberOfScalarOutputs = model->GetNumberOfScalarOutputs();
  assert(scalarOutputNames.size() == numberOfScalarOutputs);
  assert (numberOfScalarOutputs > 0);
  std::vector< double > observedScalarValues(numberOfScalarOutputs, 0.0);
  std::vector< double > observedScalarCovariance(
      numberOfScalarOutputs * numberOfScalarOutputs, 0.0);
  for (unsigned int j = 0; j < numberOfScalarOutputs; ++j)
    observedScalarCovariance[j * (1 + numberOfScalarOutputs)] = 1.0;
  while (true) { // will loop forever if input stream lasts forever.
    std::string name;
    double value, uncertainty;
    if(! (i >> name >> value >> uncertainty))
      break;
    int index = findIndex(scalarOutputNames, name);
    if (index != -1) {
      observedScalarValues[index] = value;
      // observedScalarCovariance is a square matrix;
      observedScalarCovariance[index * (1 + numberOfScalarOutputs)] = std::pow(uncertainty, 2);
      // uncertainty^2 is variance.
    }
  }
  // assume extra values are all zero.
  Model::ErrorType e;
  e = model->SetObservedScalarValues(observedScalarValues);
  if (e != madai::Model::NO_ERROR) {
    std::cerr << "Error in Model::SetObservedScalarValues\n";
    return e;
  }
  e = model->SetObservedScalarCovariance(observedScalarCovariance);
  if (e != madai::Model::NO_ERROR) {
    std::cerr << "Error in Model::SetObservedScalarCovariance\n";
    return e;
  }
  return madai::Model::NO_ERROR;
}

struct PercentileGridRuntimeParameters
{
  int numberIter;
  std::string ModelOutputDirectory;
  std::string ExperimentalResultsDirectory;
};

bool parsePGRuntimeParameters(
    int argc, char** argv,
    struct PercentileGridRuntimeParameters & Opts )
{
  // Initialize as defaults
  Opts.ModelOutputDirectory = madai::Paths::DEFAULT_MODEL_OUTPUT_DIRECTORY;
  Opts.ExperimentalResultsDirectory = madai::Paths::DEFAULT_EXPERIMENTAL_RESULTS_DIRECTORY;
  Opts.numberIter = DEFAULT_PERCENTILE_GRID_SAMPLES;

  for ( unsigned int i = 0; i < argc; i++ ) {
    std::string argString( argv[i] );

    if ( argString == "MODEL_OUTPUT_DIRECTORY" ) {
      Opts.ModelOutputDirectory = std::string( argv[i+1] );
      i++;
    } else if ( argString == "EXPERIMENTAL_RESULTS_DIRECTORY" ) {
      Opts.ExperimentalResultsDirectory = std::string( argv[i+1] );
      i++;
    } else if ( argString == "PERCENTILE_GRID_SAMPLES" ) {
      Opts.numberIter = atoi( argv[i+1] );
      if ( Opts.numberIter <= 0 ) {
        std::cerr << "Error: PERCENTILE_GRID_SAMPLES given incorrect argument \""
          << Opts.numberIter << "\"\n";
      }
      i++;
    }
  }
  return true;
}

/**
   \fixme document
 */
int main(int argc, char ** argv) {

  if (argc < 3) {
    std::cerr << "Useage:\n"
              << "    generatePercentileGridTrace <StatisticsDirectory> <OutputFileName>\n"
              << "\n"
              << "This file generates a sampling of an emulated model on a\n"
              << "regular lattice of sample points.\n"
              << "\n"
              << "<StatisticsDirectory> is the directory in which all \n"
              << "statistics data are stored. It contains the parameter file "
              << Paths::RUNTIME_PARAMETER_FILE << "\n"
              << "\n"
              << "<OutputFileName> is the name of the comma-separated value-format \n"
              << "file in which the trace will be written. This file will be \n"
              << "written in the directory <StatisticsDirectory>/trace/.\n"
              << "\n"
              << "Format of entries in " << Paths::RUNTIME_PARAMETER_FILE
              << ":\n\n"
              << "MODEL_OUTPUT_DIRECTORY <value> (default: "
              << Paths::DEFAULT_MODEL_OUTPUT_DIRECTORY << ")\n"
              << "EXPERIMENTAL_RESULTS_DIRECTORY <value> (default: "
              << Paths::DEFAULT_EXPERIMENTAL_RESULTS_DIRECTORY << ")\n"
              << "PERCENTILE_GRID_SAMPLES <value> (default: "
              << DEFAULT_PERCENTILE_GRID_SAMPLES << ")\n";
    return EXIT_FAILURE;
  }
  std::string StatisticsDirectory( argv[1] );
  std::string OutputFileName( argv[2] );

  madai::EnsurePathSeparatorAtEnd( StatisticsDirectory );
  madai::RuntimeParameterFileReader RPFR;
  RPFR.ParseFile( StatisticsDirectory + madai::Paths::RUNTIME_PARAMETER_FILE );
  char** Args = RPFR.GetArguments();
  int NArgs = RPFR.GetNumberOfArguments();
  struct PercentileGridRuntimeParameters Opts;
  if ( !parsePGRuntimeParameters( NArgs, Args, Opts ) ) {
    std::cerr << "Error: Parsing configuration file for gaussian process percentile grid.\n";
    return EXIT_FAILURE;
  }
  madai::GaussianProcessEmulatedModel gpem;
  std::string MOD = StatisticsDirectory + Opts.ModelOutputDirectory;
  std::string ERD = StatisticsDirectory + Opts.ExperimentalResultsDirectory;
  if ( gpem.LoadConfiguration( StatisticsDirectory, MOD, ERD ) != madai::Model::NO_ERROR ) {
    std::cerr << "error in GaussianProcessEmulatedModel::LoadConfiguration\n";
    return EXIT_FAILURE;
  }

  gpem.SetUseModelCovarianceToCalulateLogLikelihood(false);

  std::string observationsFile = ERD + madai::Paths::SEPARATOR + madai::Paths::RESULTS_FILE;
  std::ifstream observations( observationsFile.c_str() );
  if (madai::Model::NO_ERROR != LoadObservations(&gpem, observations)) {
    std::cerr << "error loading observations.\n";
    return EXIT_FAILURE;
  }
  observations.close();

  madai::PercentileGridSampler sampler;
  sampler.SetModel( &gpem );
  sampler.SetNumberSamples(Opts.numberIter);
  int numberIter = sampler.GetNumberSamples();

  std::vector< madai::Parameter > const & parameters
    = gpem.GetParameters();

  madai::Trace trace;

  int step = numberIter / 100, percent = 0;
  for (int count = 0; count < numberIter; count ++) {
    if (count % step == 0)
      std::cerr <<  '\r' << percent++ << "%";
    trace.Add(sampler.NextSample());
  }
  std::cerr << "\r" ;

  std::string traceDirectory = StatisticsDirectory + madai::Paths::TRACE_DIRECTORY;
  madaisys::SystemTools::MakeDirectory( traceDirectory.c_str() );
  std::string OutputFile = traceDirectory + OutputFileName;
  std::ofstream Out( OutputFile.c_str() );
  trace.WriteCSVOutput(
      Out,
      gpem.GetParameters(),
      gpem.GetScalarOutputNames() );
  return EXIT_SUCCESS;
}
<commit_msg>Cleaned up generatePercentileGridTrace<commit_after>/*=========================================================================
 *
 *  Copyright 2011-2013 The University of North Carolina at Chapel Hill
 *  All rights reserved.
 *
 *  Licensed under the MADAI Software License. You may obtain a copy of
 *  this license at
 *
 *         https://madai-public.cs.unc.edu/software/license/
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

#include "PercentileGridSampler.h"
#include "GaussianProcessEmulatedModel.h"
#include "RuntimeParameterFileReader.h"
#include "ApplicationUtilities.h"
#include "Paths.h"
#include "Trace.h"

#include "madaisys/SystemTools.hxx"

using madai::Model;
using madai::Paths;

static const int DEFAULT_PERCENTILE_GRID_NUMBER_OF_SAMPLES = 100;

template<class S, class T>
int findIndex(const S & v, const T & s)
{
  typename S::const_iterator it = std::find(v.begin(), v.end(), s);
  if (it == v.end())
    return -1;
  return std::distance(v.begin(), it);
}

/**
   Load a file with experimental observations in it.  The model will
   be compared against this. */
Model::ErrorType
LoadObservations(Model * model, std::istream & i)
{
  // std::ifstream i("DIRECTORY/experimental_results/results.dat");
  const std::vector< std::string > & scalarOutputNames = model->GetScalarOutputNames();
  unsigned int numberOfScalarOutputs = model->GetNumberOfScalarOutputs();
  assert(scalarOutputNames.size() == numberOfScalarOutputs);
  assert (numberOfScalarOutputs > 0);
  std::vector< double > observedScalarValues(numberOfScalarOutputs, 0.0);
  std::vector< double > observedScalarCovariance(
      numberOfScalarOutputs * numberOfScalarOutputs, 0.0);
  for (unsigned int j = 0; j < numberOfScalarOutputs; ++j)
    observedScalarCovariance[j * (1 + numberOfScalarOutputs)] = 1.0;
  while (true) { // will loop forever if input stream lasts forever.
    std::string name;
    double value, uncertainty;
    if(! (i >> name >> value >> uncertainty))
      break;
    int index = findIndex(scalarOutputNames, name);
    if (index != -1) {
      observedScalarValues[index] = value;
      // observedScalarCovariance is a square matrix;
      observedScalarCovariance[index * (1 + numberOfScalarOutputs)] = std::pow(uncertainty, 2);
      // uncertainty^2 is variance.
    }
  }
  // assume extra values are all zero.
  Model::ErrorType e;
  e = model->SetObservedScalarValues(observedScalarValues);
  if (e != madai::Model::NO_ERROR) {
    std::cerr << "Error in Model::SetObservedScalarValues\n";
    return e;
  }
  e = model->SetObservedScalarCovariance(observedScalarCovariance);
  if (e != madai::Model::NO_ERROR) {
    std::cerr << "Error in Model::SetObservedScalarCovariance\n";
    return e;
  }
  return madai::Model::NO_ERROR;
}

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

  if (argc < 3) {
    std::cerr << "Usage:\n"
              << "    generatePercentileGridTrace <StatisticsDirectory> <OutputFileName>\n"
              << "\n"
              << "This file generates a sampling of an emulated model on a\n"
              << "regular lattice of sample points.\n"
              << "\n"
              << "<StatisticsDirectory> is the directory in which all \n"
              << "statistics data are stored. It contains the parameter file "
              << Paths::RUNTIME_PARAMETER_FILE << "\n"
              << "\n"
              << "<OutputFileName> is the name of the comma-separated value-format \n"
              << "file in which the trace will be written. This file will be \n"
              << "written in the directory <StatisticsDirectory>/trace/.\n"
              << "\n"
              << "Format of entries in " << Paths::RUNTIME_PARAMETER_FILE
              << ":\n\n"
              << "MODEL_OUTPUT_DIRECTORY <value> (default: "
              << Paths::DEFAULT_MODEL_OUTPUT_DIRECTORY << ")\n"
              << "EXPERIMENTAL_RESULTS_DIRECTORY <value> (default: "
              << Paths::DEFAULT_EXPERIMENTAL_RESULTS_DIRECTORY << ")\n"
              << "PERCENTILE_GRID_NUMBER_OF_SAMPLES <value> (default: "
              << DEFAULT_PERCENTILE_GRID_NUMBER_OF_SAMPLES << ")\n";
    return EXIT_FAILURE;
  }
  std::string statisticsDirectory( argv[1] );
  madai::EnsurePathSeparatorAtEnd( statisticsDirectory );

  madai::RuntimeParameterFileReader settings;
  std::string settingsFile = statisticsDirectory + madai::Paths::RUNTIME_PARAMETER_FILE;
  if ( !settings.ParseFile( settingsFile ) ) {
    std::cerr << "Could not open runtime parameter file '" << settingsFile << "'\n";
    return EXIT_FAILURE;
  }

  std::string modelOutputDirectory =
    madai::GetModelOutputDirectory( statisticsDirectory, settings );
  std::string experimentalResultsDirectory =
    madai::GetExperimentalResultsDirectory( statisticsDirectory, settings );

  int numberOfSamples = DEFAULT_PERCENTILE_GRID_NUMBER_OF_SAMPLES;
  if ( settings.HasOption( "PERCENTILE_GRID_NUMBER_OF_SAMPLES" ) ) {
    numberOfSamples = atoi( settings.GetOption( "PERCENTILE_GRID_NUMBER_OF_SAMPLES" ).c_str() );
  }

  madai::GaussianProcessEmulatedModel gpem;
  if ( gpem.LoadConfiguration( statisticsDirectory,
                               modelOutputDirectory,
                               experimentalResultsDirectory ) != madai::Model::NO_ERROR ) {
    std::cerr << "Error in GaussianProcessEmulatedModel::LoadConfiguration\n";
    return EXIT_FAILURE;
  }

  gpem.SetUseModelCovarianceToCalulateLogLikelihood( false );

  std::string observationsFile = experimentalResultsDirectory + Paths::SEPARATOR +
    Paths::RESULTS_FILE;
  std::ifstream observations( observationsFile.c_str() );
  if ( madai::Model::NO_ERROR != LoadObservations( &gpem, observations ) ) {
    std::cerr << "Error loading observations.\n";
    return EXIT_FAILURE;
  }
  observations.close();

  madai::PercentileGridSampler sampler;
  sampler.SetModel( &gpem );
  sampler.SetNumberSamples( numberOfSamples );
  numberOfSamples = sampler.GetNumberSamples();

  std::vector< madai::Parameter > const & parameters = gpem.GetParameters();

  madai::Trace trace;

  int step = numberOfSamples / 100, percent = 0;
  for (int count = 0; count < numberOfSamples; count ++) {
    if (count % step == 0)
      std::cout <<  '\r' << percent++ << "%";
    trace.Add(sampler.NextSample());
  }
  std::cout << "\r" ;

  std::string traceDirectory = statisticsDirectory + madai::Paths::TRACE_DIRECTORY;
  madaisys::SystemTools::MakeDirectory( traceDirectory.c_str() );
  std::string outputFileName( argv[2] );
  std::string outputFile = traceDirectory + Paths::SEPARATOR + outputFileName;
  std::ofstream out( outputFile.c_str() );
  trace.WriteCSVOutput( out,
                        gpem.GetParameters(),
                        gpem.GetScalarOutputNames() );

  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/*
    Copyright 2008 Brain Research Institute, Melbourne, Australia

    Written by J-Donald Tournier, 27/06/08.

    This file is part of MRtrix.

    MRtrix is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    MRtrix is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with MRtrix.  If not, see <http://www.gnu.org/licenses/>.

*/

#include <fstream>
#include <set>

#include "app.h"
#include "progressbar.h"
#include "get_set.h"
#include "image/voxel.h"
#include "dataset/misc.h"
#include "dataset/buffer.h"
#include "dataset/interp/linear.h"
#include "thread/exec.h"
#include "thread/queue.h"
#include "math/hermite.h"
#include "dwi/tractography/file.h"
#include "dwi/tractography/properties.h"

using namespace MR;
using namespace MR::DWI;
using namespace std;

SET_VERSION_DEFAULT;

DESCRIPTION = {
  "convert a tracks file into a map of the fraction of tracks to enter each voxel.",
  NULL
};

ARGUMENTS = {
  Argument ("tracks", "track file", "the input track file.").type_file (),
  Argument ("template", "template image", "an image file to be used as a template for the output (the output image wil have the same voxel size and dimensions).").type_image_in(),
  Argument ("output", "output image", "the output fraction image").type_image_out(),
  Argument::End
};

OPTIONS = {
  Option ("fraction", "output fibre fraction", "produce an image of the fraction of fibres through each voxel (as a proportion of the total number in the file), rather than the count."),

  Option ("datatype", "data type", "specify output image data type.")
    .append (Argument ("spec", "specifier", "the data type specifier.").type_choice (DataType::identifiers)),

  Option ("resample", "resample tracks", "resample the tracks at regular intervals using Hermite interpolation.")
    .append (Argument ("factor", "factor", "the factor by which to resample.").type_integer (1, INT_MAX, 1)),

  Option::End
};

class Voxel
{
  public:
    Voxel () { }
    Voxel (const Point& p) :
      x (Math::round<size_t> (p[0])),
      y (Math::round<size_t> (p[1])),
      z (Math::round<size_t> (p[2])) { }

    bool operator< (const Voxel& v) const
    {
      if (x < v.x) return (true);
      if (x > v.x) return (false);
      if (y < v.y) return (true);
      if (y > v.y) return (false);
      if (z < v.z) return (true);
      return (false);
    }

    size_t x, y, z;
};

typedef Thread::Queue<std::vector<Point> > Queue1;
typedef Thread::Queue<std::set<Voxel> > Queue2;

class TrackLoader
{
  public:
    TrackLoader (Queue1& queue, DWI::Tractography::Reader& file, size_t count) :
      writer (queue),
      reader (file),
      total_count (count) { }

    void execute ()
    {
      Queue1::Writer::Item item (writer);

      ProgressBar progress ("mapping tracks to image...", total_count);
      while (reader.next (*item)) {
        if (!item.write())
          throw Exception ("error writing to track-mapping queue!");
        ++progress;
      }
    }

  private:
    Queue1::Writer writer;
    DWI::Tractography::Reader& reader;
    size_t total_count;
};

class TrackMapper
{
  public:
    TrackMapper (Queue1& input, Queue2& output, const Image::Header& header, const Math::Matrix<float>* resample_matrix = NULL) :
      reader (input),
      writer (output),
      H (header),
      resampler (resample_matrix) {
      }

    void execute ()
    {
      Queue1::Reader::Item in (reader);
      Queue2::Writer::Item out (writer);
      DataSet::Interp::Linear<const Image::Header> interp (H);
      Math::Matrix<float> resampled, orig (4,3);
      if (resampler)
        resampled.allocate (resampler->rows(), 3);

      while (in.read()) {
        out->clear();
        for (std::vector<Point>::const_iterator i = in->begin(); i != in->end(); ++i) {
          out->insert (Voxel (interp.scanner2voxel (*i)));
          if (resampler) { // TODO: this is not complete!!!
            Math::mult (resampled, *resampler, orig);
          }
        }

        if (!out.write())
          throw Exception ("error writing to write-back queue!");
      }
    }

  private:
    Queue1::Reader reader;
    Queue2::Writer writer;
    const Image::Header& H;
    const Math::Matrix<float>* resampler;
};

class MapWriter
{
  public:
    MapWriter (Queue2& queue, const Image::Header& header, bool fraction_scaling_factor) :
      reader (queue),
      H (header),
      buffer (H, "buffer"),
      interp (H),
      scale (fraction_scaling_factor)
    {
    }

    ~MapWriter ()
    {
      if (scale) {
        Image::Voxel<float> vox (H);
        DataSet::Loop loop ("writing data back to image...", 0, 3);
        for (loop.start (vox, buffer); loop.ok(); loop.next (vox, buffer))
          vox.value() = scale * buffer.value();
      }
      else {
        Image::Voxel<size_t> vox (H);
        DataSet::copy_with_progress_message ("writing data back to image...", vox, buffer, 0, 3);
      }
    }

    void execute ()
    {
      Queue2::Reader::Item item (reader);
      while (item.read()) {
        for (std::set<Voxel>::const_iterator i = item->begin(); i != item->end(); ++i) {
          buffer[0] = i->x;
          buffer[1] = i->y;
          buffer[2] = i->z;
          buffer.value() += 1;
        }
      }
    }

  private:
    Queue2::Reader reader;
    const Image::Header& H;
    DataSet::Buffer<size_t,3> buffer;
    DataSet::Interp::Linear<const Image::Header> interp;
    float scale;
};

EXECUTE {

  Image::Header header (argument[1].get_image());

  bool fibre_fraction = get_options("count").size();

  std::vector<OptBase> opt = get_options ("datatype");
  if (opt.size())
    header.datatype().parse (DataType::identifiers[opt[0][0].get_int()]);
  else
    header.datatype() = fibre_fraction ? DataType::Float32 : DataType::UInt32;

  Tractography::Properties properties;
  Tractography::Reader file;
  file.open (argument[0].get_string(), properties);

  header.axes.ndim() = 3;
  header.comments.push_back (std::string ("track ") + (fibre_fraction ? "fraction" : "count") + " map");
  for (Tractography::Properties::iterator i = properties.begin(); i != properties.end(); ++i)
    header.comments.push_back (i->first + ": " + i->second);
  for (std::multimap<std::string,std::string>::const_iterator i = properties.roi.begin(); i != properties.roi.end(); ++i)
    header.comments.push_back ("ROI: " + i->first + " " + i->second);
  for (std::vector<std::string>::iterator i = properties.comments.begin(); i != properties.comments.end(); ++i)
    header.comments.push_back ("comment: " + *i);

  const Image::Header header_out = argument[2].get_image (header);

  size_t total_count = properties["total_count"].empty() ? 0 : to<size_t> (properties["total_count"]);
  size_t num_tracks = properties["count"].empty() ? 0 : to<size_t> (properties["count"]);

  Queue1 queue1 ("loaded tracks");
  Queue2 queue2 ("processed tracks");

  TrackLoader loader (queue1, file, num_tracks);
  TrackMapper mapper (queue1, queue2, header_out);
  MapWriter writer (queue2, header_out, total_count ? 1.0 / total_count : 0.0);

  Thread::Exec loader_thread (loader, "loader");
  Thread::Array<TrackMapper> mapper_list (mapper);
  Thread::Exec mapper_threads (mapper_list, "mapper");

  writer.execute();
}

<commit_msg>minor change in tckmap help page<commit_after>/*
    Copyright 2008 Brain Research Institute, Melbourne, Australia

    Written by J-Donald Tournier, 27/06/08.

    This file is part of MRtrix.

    MRtrix is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    MRtrix is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with MRtrix.  If not, see <http://www.gnu.org/licenses/>.

*/

#include <fstream>
#include <set>

#include "app.h"
#include "progressbar.h"
#include "get_set.h"
#include "image/voxel.h"
#include "dataset/misc.h"
#include "dataset/buffer.h"
#include "dataset/interp/linear.h"
#include "thread/exec.h"
#include "thread/queue.h"
#include "math/hermite.h"
#include "dwi/tractography/file.h"
#include "dwi/tractography/properties.h"

using namespace MR;
using namespace MR::DWI;
using namespace std;

SET_VERSION_DEFAULT;

DESCRIPTION = {
  "convert a tracks file into a map of the number of tracks to enter each voxel.",
  NULL
};

ARGUMENTS = {
  Argument ("tracks", "track file", "the input track file.").type_file (),
  Argument ("template", "template image", "an image file to be used as a template for the output (the output image wil have the same voxel size and dimensions).").type_image_in(),
  Argument ("output", "output image", "the output fraction image").type_image_out(),
  Argument::End
};

OPTIONS = {
  Option ("fraction", "output fibre fraction", "produce an image of the fraction of fibres through each voxel (as a proportion of the total number in the file), rather than the count."),

  Option ("datatype", "data type", "specify output image data type.")
    .append (Argument ("spec", "specifier", "the data type specifier.").type_choice (DataType::identifiers)),

  Option ("resample", "resample tracks", "resample the tracks at regular intervals using Hermite interpolation.")
    .append (Argument ("factor", "factor", "the factor by which to resample.").type_integer (1, INT_MAX, 1)),

  Option::End
};

class Voxel
{
  public:
    Voxel () { }
    Voxel (const Point& p) :
      x (Math::round<size_t> (p[0])),
      y (Math::round<size_t> (p[1])),
      z (Math::round<size_t> (p[2])) { }

    bool operator< (const Voxel& v) const
    {
      if (x < v.x) return (true);
      if (x > v.x) return (false);
      if (y < v.y) return (true);
      if (y > v.y) return (false);
      if (z < v.z) return (true);
      return (false);
    }

    size_t x, y, z;
};

typedef Thread::Queue<std::vector<Point> > Queue1;
typedef Thread::Queue<std::set<Voxel> > Queue2;

class TrackLoader
{
  public:
    TrackLoader (Queue1& queue, DWI::Tractography::Reader& file, size_t count) :
      writer (queue),
      reader (file),
      total_count (count) { }

    void execute ()
    {
      Queue1::Writer::Item item (writer);

      ProgressBar progress ("mapping tracks to image...", total_count);
      while (reader.next (*item)) {
        if (!item.write())
          throw Exception ("error writing to track-mapping queue!");
        ++progress;
      }
    }

  private:
    Queue1::Writer writer;
    DWI::Tractography::Reader& reader;
    size_t total_count;
};

class TrackMapper
{
  public:
    TrackMapper (Queue1& input, Queue2& output, const Image::Header& header, const Math::Matrix<float>* resample_matrix = NULL) :
      reader (input),
      writer (output),
      H (header),
      resampler (resample_matrix) {
      }

    void execute ()
    {
      Queue1::Reader::Item in (reader);
      Queue2::Writer::Item out (writer);
      DataSet::Interp::Linear<const Image::Header> interp (H);
      Math::Matrix<float> resampled, orig (4,3);
      if (resampler)
        resampled.allocate (resampler->rows(), 3);

      while (in.read()) {
        out->clear();
        for (std::vector<Point>::const_iterator i = in->begin(); i != in->end(); ++i) {
          out->insert (Voxel (interp.scanner2voxel (*i)));
          if (resampler) { // TODO: this is not complete!!!
            Math::mult (resampled, *resampler, orig);
          }
        }

        if (!out.write())
          throw Exception ("error writing to write-back queue!");
      }
    }

  private:
    Queue1::Reader reader;
    Queue2::Writer writer;
    const Image::Header& H;
    const Math::Matrix<float>* resampler;
};

class MapWriter
{
  public:
    MapWriter (Queue2& queue, const Image::Header& header, bool fraction_scaling_factor) :
      reader (queue),
      H (header),
      buffer (H, "buffer"),
      interp (H),
      scale (fraction_scaling_factor)
    {
    }

    ~MapWriter ()
    {
      if (scale) {
        Image::Voxel<float> vox (H);
        DataSet::Loop loop ("writing data back to image...", 0, 3);
        for (loop.start (vox, buffer); loop.ok(); loop.next (vox, buffer))
          vox.value() = scale * buffer.value();
      }
      else {
        Image::Voxel<size_t> vox (H);
        DataSet::copy_with_progress_message ("writing data back to image...", vox, buffer, 0, 3);
      }
    }

    void execute ()
    {
      Queue2::Reader::Item item (reader);
      while (item.read()) {
        for (std::set<Voxel>::const_iterator i = item->begin(); i != item->end(); ++i) {
          buffer[0] = i->x;
          buffer[1] = i->y;
          buffer[2] = i->z;
          buffer.value() += 1;
        }
      }
    }

  private:
    Queue2::Reader reader;
    const Image::Header& H;
    DataSet::Buffer<size_t,3> buffer;
    DataSet::Interp::Linear<const Image::Header> interp;
    float scale;
};

EXECUTE {

  Image::Header header (argument[1].get_image());

  bool fibre_fraction = get_options("count").size();

  std::vector<OptBase> opt = get_options ("datatype");
  if (opt.size())
    header.datatype().parse (DataType::identifiers[opt[0][0].get_int()]);
  else
    header.datatype() = fibre_fraction ? DataType::Float32 : DataType::UInt32;

  Tractography::Properties properties;
  Tractography::Reader file;
  file.open (argument[0].get_string(), properties);

  header.axes.ndim() = 3;
  header.comments.push_back (std::string ("track ") + (fibre_fraction ? "fraction" : "count") + " map");
  for (Tractography::Properties::iterator i = properties.begin(); i != properties.end(); ++i)
    header.comments.push_back (i->first + ": " + i->second);
  for (std::multimap<std::string,std::string>::const_iterator i = properties.roi.begin(); i != properties.roi.end(); ++i)
    header.comments.push_back ("ROI: " + i->first + " " + i->second);
  for (std::vector<std::string>::iterator i = properties.comments.begin(); i != properties.comments.end(); ++i)
    header.comments.push_back ("comment: " + *i);

  const Image::Header header_out = argument[2].get_image (header);

  size_t total_count = properties["total_count"].empty() ? 0 : to<size_t> (properties["total_count"]);
  size_t num_tracks = properties["count"].empty() ? 0 : to<size_t> (properties["count"]);

  Queue1 queue1 ("loaded tracks");
  Queue2 queue2 ("processed tracks");

  TrackLoader loader (queue1, file, num_tracks);
  TrackMapper mapper (queue1, queue2, header_out);
  MapWriter writer (queue2, header_out, total_count ? 1.0 / total_count : 0.0);

  Thread::Exec loader_thread (loader, "loader");
  Thread::Array<TrackMapper> mapper_list (mapper);
  Thread::Exec mapper_threads (mapper_list, "mapper");

  writer.execute();
}

<|endoftext|>


<commit_before>#include "cnn/devices.h"

#include <boost/algorithm/string.hpp>
#include <iostream>
#include <unsupported/Eigen/CXX11/Tensor>

#include "cnn/cuda.h"
#include "cnn/cnn.h"

using namespace std;

namespace cnn {

DeviceMempoolSizes::DeviceMempoolSizes(size_t total_size) {
  used[0] = total_size/3;
  used[1] = total_size/3;
  used[2] = total_size/3;
}

DeviceMempoolSizes::DeviceMempoolSizes(size_t fx_s, size_t dEdfs_s, size_t ps_s) {
  used[0] = fx_s;
  used[1] = dEdfs_s;
  used[2] = ps_s;
}

DeviceMempoolSizes::DeviceMempoolSizes(const std::string & descriptor) {
  vector<string> strs;
  boost::algorithm::split(strs, descriptor, boost::is_any_of(","));
  if(strs.size() == 1) {
    size_t total_size = stoi(strs[0]);
    used[0] = total_size/3;
    used[1] = total_size/3;
    used[2] = total_size/3;
  } else if(strs.size() == 3) {
    used[0] = stoi(strs[0]);
    used[1] = stoi(strs[1]);
    used[2] = stoi(strs[2]);
  }
}

Device::~Device() {}

DeviceMempoolSizes Device::mark(ComputationGraph *cg) {
  cg->incremental_forward(); // needed so that we actually allocate the needed memory
                             // for all existing nodes.
  return DeviceMempoolSizes(pools[0]->used, pools[1]->used, pools[2]->used);
}

void Device::revert(const DeviceMempoolSizes & cp) {
  assert(cp.used[0] <= pools[0]->used);
  pools[0]->used = cp.used[0];
  assert(cp.used[1] <= pools[1]->used);
  pools[1]->used = cp.used[1];
  assert(cp.used[2] <= pools[2]->used);
  pools[2]->used = cp.used[2];
}

void Device::allocate_tensor(DeviceMempool mp, Tensor & tens) {
  assert(mp != DeviceMempool::NONE);
  assert(pools[(int)mp] != nullptr);
  tens.v = (float*)pools[(int)mp]->allocate(tens.d.size() * sizeof(float));
  tens.mem_pool = mp;
}

#if HAVE_CUDA
Device_GPU::Device_GPU(int my_id, const DeviceMempoolSizes & mbs, int device_id) :
    Device(my_id, DeviceType::GPU, &gpu_mem), cuda_device_id(device_id), gpu_mem(device_id) {
  CUDA_CHECK(cudaSetDevice(device_id));
  CUBLAS_CHECK(cublasCreate(&cublas_handle));
  CUBLAS_CHECK(cublasSetPointerMode(cublas_handle, CUBLAS_POINTER_MODE_DEVICE));
  kSCALAR_MINUSONE = (float*)gpu_mem.malloc(sizeof(float));
  kSCALAR_ONE = (float*)gpu_mem.malloc(sizeof(float));
  kSCALAR_ZERO = (float*)gpu_mem.malloc(sizeof(float));
  float minusone = -1;
  CUDA_CHECK(cudaMemcpyAsync(kSCALAR_MINUSONE, &minusone, sizeof(float), cudaMemcpyHostToDevice));
  float one = 1;
  CUDA_CHECK(cudaMemcpyAsync(kSCALAR_ONE, &one, sizeof(float), cudaMemcpyHostToDevice));
  float zero = 0;
  CUDA_CHECK(cudaMemcpyAsync(kSCALAR_ZERO, &zero, sizeof(float), cudaMemcpyHostToDevice));

  // Initialize the Eigen device
  estream = new Eigen::CudaStreamDevice(device_id);
  edevice = new Eigen::GpuDevice(estream);

  // this is the big memory allocation.
  for(size_t i = 0; i < 3; ++i)
    pools[i] = new AlignedMemoryPool((mbs.used[i] << 20), &gpu_mem);
}

Device_GPU::~Device_GPU() {}
#endif

Device_CPU::Device_CPU(int my_id, const DeviceMempoolSizes & mbs, bool shared) :
    Device(my_id, DeviceType::CPU, &cpu_mem), shmem(mem) {
  if (shared) shmem = new SharedAllocator();
  kSCALAR_MINUSONE = (float*) mem->malloc(sizeof(float));
  *kSCALAR_MINUSONE = -1;
  kSCALAR_ONE = (float*) mem->malloc(sizeof(float));
  *kSCALAR_ONE = 1;
  kSCALAR_ZERO = (float*) mem->malloc(sizeof(float));
  *kSCALAR_ZERO = 0;

  // Initialize the Eigen device
  edevice = new Eigen::DefaultDevice;

  // this is the big memory allocation.
  for(size_t i = 0; i < 3; ++i)
    pools[i] = new AlignedMemoryPool((mbs.used[i] << 20), &cpu_mem);
}

Device_CPU::~Device_CPU() {}

} // namespace cnn
<commit_msg>Fixed accidental removal of support for shared memory parameters<commit_after>#include "cnn/devices.h"

#include <boost/algorithm/string.hpp>
#include <iostream>
#include <unsupported/Eigen/CXX11/Tensor>

#include "cnn/cuda.h"
#include "cnn/cnn.h"

using namespace std;

namespace cnn {

DeviceMempoolSizes::DeviceMempoolSizes(size_t total_size) {
  used[0] = total_size/3;
  used[1] = total_size/3;
  used[2] = total_size/3;
}

DeviceMempoolSizes::DeviceMempoolSizes(size_t fx_s, size_t dEdfs_s, size_t ps_s) {
  used[0] = fx_s;
  used[1] = dEdfs_s;
  used[2] = ps_s;
}

DeviceMempoolSizes::DeviceMempoolSizes(const std::string & descriptor) {
  vector<string> strs;
  boost::algorithm::split(strs, descriptor, boost::is_any_of(","));
  if(strs.size() == 1) {
    size_t total_size = stoi(strs[0]);
    used[0] = total_size/3;
    used[1] = total_size/3;
    used[2] = total_size/3;
  } else if(strs.size() == 3) {
    used[0] = stoi(strs[0]);
    used[1] = stoi(strs[1]);
    used[2] = stoi(strs[2]);
  }
}

Device::~Device() {}

DeviceMempoolSizes Device::mark(ComputationGraph *cg) {
  cg->incremental_forward(); // needed so that we actually allocate the needed memory
                             // for all existing nodes.
  return DeviceMempoolSizes(pools[0]->used, pools[1]->used, pools[2]->used);
}

void Device::revert(const DeviceMempoolSizes & cp) {
  assert(cp.used[0] <= pools[0]->used);
  pools[0]->used = cp.used[0];
  assert(cp.used[1] <= pools[1]->used);
  pools[1]->used = cp.used[1];
  assert(cp.used[2] <= pools[2]->used);
  pools[2]->used = cp.used[2];
}

void Device::allocate_tensor(DeviceMempool mp, Tensor & tens) {
  assert(mp != DeviceMempool::NONE);
  assert(pools[(int)mp] != nullptr);
  tens.v = (float*)pools[(int)mp]->allocate(tens.d.size() * sizeof(float));
  tens.mem_pool = mp;
}

#if HAVE_CUDA
Device_GPU::Device_GPU(int my_id, const DeviceMempoolSizes & mbs, int device_id) :
    Device(my_id, DeviceType::GPU, &gpu_mem), cuda_device_id(device_id), gpu_mem(device_id) {
  CUDA_CHECK(cudaSetDevice(device_id));
  CUBLAS_CHECK(cublasCreate(&cublas_handle));
  CUBLAS_CHECK(cublasSetPointerMode(cublas_handle, CUBLAS_POINTER_MODE_DEVICE));
  kSCALAR_MINUSONE = (float*)gpu_mem.malloc(sizeof(float));
  kSCALAR_ONE = (float*)gpu_mem.malloc(sizeof(float));
  kSCALAR_ZERO = (float*)gpu_mem.malloc(sizeof(float));
  float minusone = -1;
  CUDA_CHECK(cudaMemcpyAsync(kSCALAR_MINUSONE, &minusone, sizeof(float), cudaMemcpyHostToDevice));
  float one = 1;
  CUDA_CHECK(cudaMemcpyAsync(kSCALAR_ONE, &one, sizeof(float), cudaMemcpyHostToDevice));
  float zero = 0;
  CUDA_CHECK(cudaMemcpyAsync(kSCALAR_ZERO, &zero, sizeof(float), cudaMemcpyHostToDevice));

  // Initialize the Eigen device
  estream = new Eigen::CudaStreamDevice(device_id);
  edevice = new Eigen::GpuDevice(estream);

  // this is the big memory allocation.
  for(size_t i = 0; i < 3; ++i)
    pools[i] = new AlignedMemoryPool((mbs.used[i] << 20), &gpu_mem);
}

Device_GPU::~Device_GPU() {}
#endif

Device_CPU::Device_CPU(int my_id, const DeviceMempoolSizes & mbs, bool shared) :
    Device(my_id, DeviceType::CPU, &cpu_mem), shmem(mem) {
  if (shared) shmem = new SharedAllocator();
  kSCALAR_MINUSONE = (float*) mem->malloc(sizeof(float));
  *kSCALAR_MINUSONE = -1;
  kSCALAR_ONE = (float*) mem->malloc(sizeof(float));
  *kSCALAR_ONE = 1;
  kSCALAR_ZERO = (float*) mem->malloc(sizeof(float));
  *kSCALAR_ZERO = 0;

  // Initialize the Eigen device
  edevice = new Eigen::DefaultDevice;

  // this is the big memory allocation.
  for(size_t i = 0; i < 2; ++i)
    pools[i] = new AlignedMemoryPool((mbs.used[i] << 20), &cpu_mem);
  pools[2] = new AlignedMemoryPool((mbs.used[2] << 20), shmem);
}

Device_CPU::~Device_CPU() {}

} // namespace cnn
<|endoftext|>