<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

#ifdef MOOSE_HAVE_LIBPNG

#include <fstream>
#include "PNGOutput.h"
#include "FEProblemBase.h"
#include "NonlinearSystem.h"
#include "AuxiliarySystem.h"
#include "libmesh/mesh_tools.h"

registerMooseObject("MooseApp", PNGOutput);

template <>
InputParameters
validParams<PNGOutput>()
{
  InputParameters params = validParams<FileOutput>();
  params.addParam<bool>("transparent_background",
                        false,
                        "Determination of whether the background will be transparent.");
  params.addRequiredParam<VariableName>("variable",
                                        "The name of the variable to use when creating the image");
  params.addParam<Real>("max", 1, "The maximum for the variable we want to use");
  params.addParam<Real>("min", 0, "The minimum for the variable we want to use");
  MooseEnum color("GRAY BRYW BWR RWB BR");
  params.addRequiredParam<MooseEnum>("color", color, "Choose the color scheme to use.");
  params.addRangeCheckedParam<unsigned int>(
      "resolution", 25, "resolution>0", "The length of the longest side of the image in pixels.");
  params.addRangeCheckedParam<Real>("out_bounds_shade",
                                    .5,
                                    "out_bounds_shade>=0 & out_bounds_shade<=1",
                                    "Color for the parts of the image that are out of bounds."
                                    "Value is between 1 and 0.");
  params.addRangeCheckedParam<Real>("transparency",
                                    1,
                                    "transparency>=0 & transparency<=1",
                                    "Value is between 0 and 1"
                                    "where 0 is completely transparent and 1 is completely opaque. "
                                    "Default transparency of the image is no transparency.");

  return params;
}

PNGOutput::PNGOutput(const InputParameters & parameters)
  : FileOutput(parameters),
    _resolution(getParam<unsigned int>("resolution")),
    _color(parameters.get<MooseEnum>("color")),
    _transparent_background(getParam<bool>("transparent_background")),
    _transparency(getParam<Real>("transparency")),
    _use_aux(false),
    _variable(getParam<VariableName>("variable")),
    _max(getParam<Real>("max")),
    _min(getParam<Real>("min")),
    _out_bounds_shade(getParam<Real>("out_bounds_shade"))
{
}

// Funtion for making the _mesh_function object.
void
PNGOutput::makeMeshFunc()
{

  // The number assigned to the variable.  Used to build the correct mesh.  Default is 0.
  unsigned int variable_number = 0;

  // PNGOutput does not currently scale for running in parallel.
  if (processor_id() != 0)
    mooseInfo("PNGOutput is not currently scalable.");

  if (_problem_ptr->getAuxiliarySystem().hasVariable(_variable))
  {
    variable_number = _problem_ptr->getAuxiliarySystem().getVariable(0, _variable).number();
    _use_aux = true;
  }

  else if (_problem_ptr->getNonlinearSystem().hasVariable(_variable))
    variable_number = _problem_ptr->getNonlinearSystem().getVariable(0, _variable).number();

  else
    paramError("variable", "This doesn't exist.");

  const std::vector<unsigned int> var_nums = {variable_number};

  // If we want the background to be transparent, we need a number over 1.
  if (_transparent_background)
    _out_bounds_shade = 2;

  // Find the values that will be used for rescaling purposes.
  calculateRescalingValues();

  // Set up the mesh_function
  if (_use_aux)
    _mesh_function =
        libmesh_make_unique<MeshFunction>(*_es_ptr,
                                          _problem_ptr->getAuxiliarySystem().serializedSolution(),
                                          _problem_ptr->getAuxiliarySystem().dofMap(),
                                          var_nums);
  else
    _mesh_function =
        libmesh_make_unique<MeshFunction>(*_es_ptr,
                                          _problem_ptr->getNonlinearSystem().serializedSolution(),
                                          _problem_ptr->getNonlinearSystem().dofMap(),
                                          var_nums);
  _mesh_function->init();

  // Need to enable out of mesh with the given control color scaled in reverse
  // so when scaling is done, this value retains it's original value.
  _mesh_function->enable_out_of_mesh_mode(reverseScale(_out_bounds_shade));
}

// Function to find the min and max values so that all the values can be scaled between the two.
void
PNGOutput::calculateRescalingValues()
{
  // The max and min.
  // If the max value wasn't specified in the input file, find it from the system.
  if (!_pars.isParamSetByUser("max"))
  {
    if (_use_aux)
      _scaling_max = _problem_ptr->getAuxiliarySystem().serializedSolution().max();
    else
      _scaling_max = _problem_ptr->getNonlinearSystem().serializedSolution().max();
  }
  else
    _scaling_max = _max;

  // If the min value wasn't specified in the input file, find it from the system.
  if (!_pars.isParamSetByUser("min"))
  {
    if (_use_aux)
      _scaling_min = _problem_ptr->getAuxiliarySystem().serializedSolution().min();
    else
      _scaling_min = _problem_ptr->getNonlinearSystem().serializedSolution().min();
  }
  else
    _scaling_min = _min;

  // The amount the values will need to be shifted.
  _shift_value = 0;

  // Get the shift value.
  if (_scaling_min != 0)
  {
    // Shiftvalue will be the same magnitude, but
    // going in the opposite direction of the scalingMin
    _shift_value -= _scaling_min;
  }

  // Shift the max.
  _scaling_max += _shift_value;
}

// Function to apply the scale to the data points.
// Needed to be able to see accurate images that cover the appropriate color spectrum.
inline Real
PNGOutput::applyScale(Real value_to_scale)
{
  return ((value_to_scale + _shift_value) / _scaling_max);
}

// Function to reverse the scaling that happens to a value.
// Needed to be able to accurately control the _out_bounds_shade.
inline Real
PNGOutput::reverseScale(Real value_to_unscale)
{
  return ((value_to_unscale * _scaling_max) - _shift_value);
}

// Function that controls the colorization of the png image for non-grayscale images.
void
PNGOutput::setRGB(png_byte * rgb, Real selection)
{
  // With this system we have a color we start with when the value is 0 and another it approaches as
  // the value increases all the way to 255.  If we want it to approach another color from that new
  // color, it will do so for the next 255, so the transition is from 256 - 511.  For each
  // additional color we want to transition to, we need another 255. Transitioning from no color, or
  // black to Red then Green then Blue then the values of from black as it becomes Red would be 0 -
  // 255, Red to Green as 256 - 511 and then Green to Blue as 512 - 767 which gives us our total
  // colorSpectrum of 0 - 767, which includes those colors and each of their states in the
  // transistion.
  unsigned int number_of_destination_colors;
  switch (_color)
  {
    // BRYW.  Three destination colors (R,Y,W).
    case 1:
      number_of_destination_colors = 3;
      break;

    // BWR.  Two destination colors (W,R).
    case 2:
      number_of_destination_colors = 2;
      break;

    // RWB.  Two destination colors (W,B).
    case 3:
      number_of_destination_colors = 2;
      break;

    // BR.   One destination color (R).
    case 4:
      number_of_destination_colors = 1;
      break;
  }

  // We need to convert the number of colors into the spectrum max, then convert the value from the
  // mesh to a point somewhere in the range of 0 to color_spectrum_max.
  auto color_spectrum_max = (256 * number_of_destination_colors) - 1;
  auto color = (unsigned int)(selection * color_spectrum_max);

  // Unless we specifically say some part is transparent, we want the whole image to be opaque.
  auto tran = (unsigned int)(_transparency * 255);

  // Make sure everything is within our colorSpectrum.  If it's bigger, then we want a
  // transparent background.
  if (color > color_spectrum_max)
  {
    color = color_spectrum_max;
    tran = 0;
  }
  if (color < 0)
    color = 0;
  auto magnitude = color % 256;

  switch (_color)
  {
    // Current color scheme: Blue->Red->Yellow->White
    case 1:
      // Blue->Red
      if (color < 256)
      {
        rgb[0] = magnitude;
        rgb[1] = 0;
        rgb[2] = 50; // 255 - magnitude;
      }
      // Red->Yellow
      else if (color < 512)
      {
        rgb[0] = 255;
        rgb[1] = magnitude;
        rgb[2] = 0;
      }
      // Yellow->White
      else
      {
        rgb[0] = 255;
        rgb[1] = 255;
        rgb[2] = magnitude;
      }
      break;

    // Color Scheme: Blue->White->Red
    // Using the RGB values found in Paraview
    case 2:
      // Blue->White
      if (color < 256)
      {
        rgb[0] = (int)(255.0 * (0.231373 + (0.002485 * (float)magnitude)));
        rgb[1] = (int)(255.0 * (0.298039 + (0.002223 * (float)magnitude)));
        rgb[2] = (int)(255.0 * (0.752941 + (0.000439 * (float)magnitude)));
      }
      // White->Red
      else
      {
        rgb[0] = (int)(255.0 * (0.865003 - (0.000624 * (float)magnitude)));
        rgb[1] = (int)(255.0 * (0.865003 - (0.003331 * (float)magnitude)));
        rgb[2] = (int)(255.0 * (0.865003 - (0.002808 * (float)magnitude)));
      }
      break;

    // Red->White->Blue
    case 3:
      // Red->White
      if (color < 256)
      {
        rgb[0] = 255;
        rgb[1] = magnitude;
        rgb[2] = magnitude;
      }
      // White->Blue
      else
      {
        rgb[0] = 255 - magnitude;
        rgb[1] = 255 - magnitude;
        rgb[2] = 255;
      }
      break;

    // Blue->Red
    case 4:
      // Blue->Red
      rgb[0] = magnitude;
      rgb[1] = 0;
      rgb[2] = 255 - magnitude;
      break;
  }
  // Add any transparency.
  rgb[3] = tran;
}

void
PNGOutput::output(const ExecFlagType & /*type*/)
{
  makeMeshFunc();
  _box = MeshTools::create_bounding_box(*_mesh_ptr);

  // Make sure this happens on processor 0
  if (processor_id() == 0)
    makePNG();
}

// Function the writes the PNG out to the appropriate filename.
void
PNGOutput::makePNG()
{
  // Get the max and min of the BoundingBox
  Point max_point = _box.max();
  Point min_point = _box.min();

  // The the total distance on the x and y axes.
  Real dist_x = max_point(0) - min_point(0);
  Real dist_y = max_point(1) - min_point(1);

  // Width and height for the PNG image.
  Real width;
  Real height;

  // Variable to record the resolution variable after normalized to work with pixels in longest
  // direction.
  Real normalized_resolution;

  // The longer dimension becomes the value to which we scale the other.
  if (dist_x > dist_y)
  {
    width = _resolution;
    height = (_resolution / dist_x) * dist_y;
    normalized_resolution = (((Real)_resolution) / dist_x);
  }
  else
  {
    height = _resolution;
    width = (_resolution / dist_y) * dist_x;
    normalized_resolution = (((Real)_resolution) / dist_y);
  }

  // Create the filename based on base and the test step number.
  std::ostringstream png_file;
  png_file << _file_base << "_" << std::setfill('0') << std::setw(3) << _t_step << ".png";

  // libpng is built on C, so by default it takes FILE*.
  FILE * fp = nullptr;
  png_structp pngp = nullptr;
  png_infop infop = nullptr;
  // Required depth for proper image clarity.
  Real depth = 8;
  // Allocate resources.
  std::vector<png_byte> row((width + 1) * 4);

  // Check if we can open and write to the file.
  MooseUtils::checkFileWriteable(png_file.str());

  // Open the file with write and bit modes.
  fp = fopen(png_file.str().c_str(), "wb");

  pngp = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
  if (!pngp)
    mooseError("Failed to make the pointer string for the png.");

  infop = png_create_info_struct(pngp);
  if (!infop)
    mooseError("Failed to make an info pointer for the png.");

  // Initializes the IO for the png.  Needs FILE* to compile.
  png_init_io(pngp, fp);

  // Set up the PNG header.
  png_set_IHDR(pngp,
               infop,
               width,
               height,
               depth,
               (_color ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_GRAY),
               PNG_INTERLACE_NONE,
               PNG_COMPRESSION_TYPE_DEFAULT,
               PNG_FILTER_TYPE_DEFAULT);

  png_write_info(pngp, infop);

  // Initiallizing the point that will be used for populating the mesh values.
  // Initializing x, y, z to zero so that we don't access the point before it's
  // been set.  z = 0 for all the png's.
  Point pt(0, 0, 0);

  // Dense vector that we can pass into the _mesh_function to fill with a value for a given point.
  DenseVector<Number> dv(0);

  // Loop through to create the image.
  for (Real y = max_point(1); y >= min_point(1); y -= 1. / normalized_resolution)
  {
    pt(1) = y;
    unsigned int index = 0;
    for (Real x = min_point(0); x <= max_point(0); x += 1. / normalized_resolution)
    {
      pt(0) = x;
      (*_mesh_function)(pt, _time, dv, nullptr);

      // Determine whether to create the PNG in color or grayscale
      if (_color)
        setRGB(&row.data()[index * 4], applyScale(dv(0)));
      else
        row.data()[index] = applyScale(dv(0)) * 255;

      index++;
    }
    png_write_row(pngp, row.data());
  }

  // Close the file and take care of some other png end stuff.
  png_write_end(pngp, nullptr);
  if (fp != nullptr)
    fclose(fp);
  if (infop != nullptr)
    png_free_data(pngp, infop, PNG_FREE_ALL, -1);
  if (pngp != nullptr)
    png_destroy_write_struct(&pngp, &infop);
}

#endif
<commit_msg>Took out a redundant test.<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

#ifdef MOOSE_HAVE_LIBPNG

#include <fstream>
#include "PNGOutput.h"
#include "FEProblemBase.h"
#include "NonlinearSystem.h"
#include "AuxiliarySystem.h"
#include "libmesh/mesh_tools.h"

registerMooseObject("MooseApp", PNGOutput);

template <>
InputParameters
validParams<PNGOutput>()
{
  InputParameters params = validParams<FileOutput>();
  params.addParam<bool>("transparent_background",
                        false,
                        "Determination of whether the background will be transparent.");
  params.addRequiredParam<VariableName>("variable",
                                        "The name of the variable to use when creating the image");
  params.addParam<Real>("max", 1, "The maximum for the variable we want to use");
  params.addParam<Real>("min", 0, "The minimum for the variable we want to use");
  MooseEnum color("GRAY BRYW BWR RWB BR");
  params.addRequiredParam<MooseEnum>("color", color, "Choose the color scheme to use.");
  params.addRangeCheckedParam<unsigned int>(
      "resolution", 25, "resolution>0", "The length of the longest side of the image in pixels.");
  params.addRangeCheckedParam<Real>("out_bounds_shade",
                                    .5,
                                    "out_bounds_shade>=0 & out_bounds_shade<=1",
                                    "Color for the parts of the image that are out of bounds."
                                    "Value is between 1 and 0.");
  params.addRangeCheckedParam<Real>("transparency",
                                    1,
                                    "transparency>=0 & transparency<=1",
                                    "Value is between 0 and 1"
                                    "where 0 is completely transparent and 1 is completely opaque. "
                                    "Default transparency of the image is no transparency.");

  return params;
}

PNGOutput::PNGOutput(const InputParameters & parameters)
  : FileOutput(parameters),
    _resolution(getParam<unsigned int>("resolution")),
    _color(parameters.get<MooseEnum>("color")),
    _transparent_background(getParam<bool>("transparent_background")),
    _transparency(getParam<Real>("transparency")),
    _use_aux(false),
    _variable(getParam<VariableName>("variable")),
    _max(getParam<Real>("max")),
    _min(getParam<Real>("min")),
    _out_bounds_shade(getParam<Real>("out_bounds_shade"))
{
}

// Funtion for making the _mesh_function object.
void
PNGOutput::makeMeshFunc()
{

  // The number assigned to the variable.  Used to build the correct mesh.  Default is 0.
  unsigned int variable_number = 0;

  // PNGOutput does not currently scale for running in parallel.
  if (processor_id() != 0)
    mooseInfo("PNGOutput is not currently scalable.");

  if (_problem_ptr->getAuxiliarySystem().hasVariable(_variable))
  {
    variable_number = _problem_ptr->getAuxiliarySystem().getVariable(0, _variable).number();
    _use_aux = true;
  }

  else if (_problem_ptr->getNonlinearSystem().hasVariable(_variable))
    variable_number = _problem_ptr->getNonlinearSystem().getVariable(0, _variable).number();

  else
    paramError("variable", "This doesn't exist.");

  const std::vector<unsigned int> var_nums = {variable_number};

  // If we want the background to be transparent, we need a number over 1.
  if (_transparent_background)
    _out_bounds_shade = 2;

  // Find the values that will be used for rescaling purposes.
  calculateRescalingValues();

  // Set up the mesh_function
  if (_use_aux)
    _mesh_function =
        libmesh_make_unique<MeshFunction>(*_es_ptr,
                                          _problem_ptr->getAuxiliarySystem().serializedSolution(),
                                          _problem_ptr->getAuxiliarySystem().dofMap(),
                                          var_nums);
  else
    _mesh_function =
        libmesh_make_unique<MeshFunction>(*_es_ptr,
                                          _problem_ptr->getNonlinearSystem().serializedSolution(),
                                          _problem_ptr->getNonlinearSystem().dofMap(),
                                          var_nums);
  _mesh_function->init();

  // Need to enable out of mesh with the given control color scaled in reverse
  // so when scaling is done, this value retains it's original value.
  _mesh_function->enable_out_of_mesh_mode(reverseScale(_out_bounds_shade));
}

// Function to find the min and max values so that all the values can be scaled between the two.
void
PNGOutput::calculateRescalingValues()
{
  // The max and min.
  // If the max value wasn't specified in the input file, find it from the system.
  if (!_pars.isParamSetByUser("max"))
  {
    if (_use_aux)
      _scaling_max = _problem_ptr->getAuxiliarySystem().serializedSolution().max();
    else
      _scaling_max = _problem_ptr->getNonlinearSystem().serializedSolution().max();
  }
  else
    _scaling_max = _max;

  // If the min value wasn't specified in the input file, find it from the system.
  if (!_pars.isParamSetByUser("min"))
  {
    if (_use_aux)
      _scaling_min = _problem_ptr->getAuxiliarySystem().serializedSolution().min();
    else
      _scaling_min = _problem_ptr->getNonlinearSystem().serializedSolution().min();
  }
  else
    _scaling_min = _min;

  // The amount the values will need to be shifted.
  _shift_value = 0;

  // Get the shift value.
  if (_scaling_min != 0)
  {
    // Shiftvalue will be the same magnitude, but
    // going in the opposite direction of the scalingMin
    _shift_value -= _scaling_min;
  }

  // Shift the max.
  _scaling_max += _shift_value;
}

// Function to apply the scale to the data points.
// Needed to be able to see accurate images that cover the appropriate color spectrum.
inline Real
PNGOutput::applyScale(Real value_to_scale)
{
  return ((value_to_scale + _shift_value) / _scaling_max);
}

// Function to reverse the scaling that happens to a value.
// Needed to be able to accurately control the _out_bounds_shade.
inline Real
PNGOutput::reverseScale(Real value_to_unscale)
{
  return ((value_to_unscale * _scaling_max) - _shift_value);
}

// Function that controls the colorization of the png image for non-grayscale images.
void
PNGOutput::setRGB(png_byte * rgb, Real selection)
{
  // With this system we have a color we start with when the value is 0 and another it approaches as
  // the value increases all the way to 255.  If we want it to approach another color from that new
  // color, it will do so for the next 255, so the transition is from 256 - 511.  For each
  // additional color we want to transition to, we need another 255. Transitioning from no color, or
  // black to Red then Green then Blue then the values of from black as it becomes Red would be 0 -
  // 255, Red to Green as 256 - 511 and then Green to Blue as 512 - 767 which gives us our total
  // colorSpectrum of 0 - 767, which includes those colors and each of their states in the
  // transistion.
  unsigned int number_of_destination_colors;
  switch (_color)
  {
    // BRYW.  Three destination colors (R,Y,W).
    case 1:
      number_of_destination_colors = 3;
      break;

    // BWR.  Two destination colors (W,R).
    case 2:
      number_of_destination_colors = 2;
      break;

    // RWB.  Two destination colors (W,B).
    case 3:
      number_of_destination_colors = 2;
      break;

    // BR.   One destination color (R).
    case 4:
      number_of_destination_colors = 1;
      break;
  }

  // We need to convert the number of colors into the spectrum max, then convert the value from the
  // mesh to a point somewhere in the range of 0 to color_spectrum_max.
  auto color_spectrum_max = (256 * number_of_destination_colors) - 1;
  auto color = (unsigned int)(selection * color_spectrum_max);

  // Unless we specifically say some part is transparent, we want the whole image to be opaque.
  auto tran = (unsigned int)(_transparency * 255);

  // Make sure everything is within our colorSpectrum.  If it's bigger, then we want a
  // transparent background.
  if (color > color_spectrum_max)
  {
    color = color_spectrum_max;
    tran = 0;
  }

  auto magnitude = color % 256;

  switch (_color)
  {
    // Current color scheme: Blue->Red->Yellow->White
    case 1:
      // Blue->Red
      if (color < 256)
      {
        rgb[0] = magnitude;
        rgb[1] = 0;
        rgb[2] = 50; // 255 - magnitude;
      }
      // Red->Yellow
      else if (color < 512)
      {
        rgb[0] = 255;
        rgb[1] = magnitude;
        rgb[2] = 0;
      }
      // Yellow->White
      else
      {
        rgb[0] = 255;
        rgb[1] = 255;
        rgb[2] = magnitude;
      }
      break;

    // Color Scheme: Blue->White->Red
    // Using the RGB values found in Paraview
    case 2:
      // Blue->White
      if (color < 256)
      {
        rgb[0] = (int)(255.0 * (0.231373 + (0.002485 * (float)magnitude)));
        rgb[1] = (int)(255.0 * (0.298039 + (0.002223 * (float)magnitude)));
        rgb[2] = (int)(255.0 * (0.752941 + (0.000439 * (float)magnitude)));
      }
      // White->Red
      else
      {
        rgb[0] = (int)(255.0 * (0.865003 - (0.000624 * (float)magnitude)));
        rgb[1] = (int)(255.0 * (0.865003 - (0.003331 * (float)magnitude)));
        rgb[2] = (int)(255.0 * (0.865003 - (0.002808 * (float)magnitude)));
      }
      break;

    // Red->White->Blue
    case 3:
      // Red->White
      if (color < 256)
      {
        rgb[0] = 255;
        rgb[1] = magnitude;
        rgb[2] = magnitude;
      }
      // White->Blue
      else
      {
        rgb[0] = 255 - magnitude;
        rgb[1] = 255 - magnitude;
        rgb[2] = 255;
      }
      break;

    // Blue->Red
    case 4:
      // Blue->Red
      rgb[0] = magnitude;
      rgb[1] = 0;
      rgb[2] = 255 - magnitude;
      break;
  }
  // Add any transparency.
  rgb[3] = tran;
}

void
PNGOutput::output(const ExecFlagType & /*type*/)
{
  makeMeshFunc();
  _box = MeshTools::create_bounding_box(*_mesh_ptr);

  // Make sure this happens on processor 0
  if (processor_id() == 0)
    makePNG();
}

// Function the writes the PNG out to the appropriate filename.
void
PNGOutput::makePNG()
{
  // Get the max and min of the BoundingBox
  Point max_point = _box.max();
  Point min_point = _box.min();

  // The the total distance on the x and y axes.
  Real dist_x = max_point(0) - min_point(0);
  Real dist_y = max_point(1) - min_point(1);

  // Width and height for the PNG image.
  Real width;
  Real height;

  // Variable to record the resolution variable after normalized to work with pixels in longest
  // direction.
  Real normalized_resolution;

  // The longer dimension becomes the value to which we scale the other.
  if (dist_x > dist_y)
  {
    width = _resolution;
    height = (_resolution / dist_x) * dist_y;
    normalized_resolution = (((Real)_resolution) / dist_x);
  }
  else
  {
    height = _resolution;
    width = (_resolution / dist_y) * dist_x;
    normalized_resolution = (((Real)_resolution) / dist_y);
  }

  // Create the filename based on base and the test step number.
  std::ostringstream png_file;
  png_file << _file_base << "_" << std::setfill('0') << std::setw(3) << _t_step << ".png";

  // libpng is built on C, so by default it takes FILE*.
  FILE * fp = nullptr;
  png_structp pngp = nullptr;
  png_infop infop = nullptr;
  // Required depth for proper image clarity.
  Real depth = 8;
  // Allocate resources.
  std::vector<png_byte> row((width + 1) * 4);

  // Check if we can open and write to the file.
  MooseUtils::checkFileWriteable(png_file.str());

  // Open the file with write and bit modes.
  fp = fopen(png_file.str().c_str(), "wb");

  pngp = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
  if (!pngp)
    mooseError("Failed to make the pointer string for the png.");

  infop = png_create_info_struct(pngp);
  if (!infop)
    mooseError("Failed to make an info pointer for the png.");

  // Initializes the IO for the png.  Needs FILE* to compile.
  png_init_io(pngp, fp);

  // Set up the PNG header.
  png_set_IHDR(pngp,
               infop,
               width,
               height,
               depth,
               (_color ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_GRAY),
               PNG_INTERLACE_NONE,
               PNG_COMPRESSION_TYPE_DEFAULT,
               PNG_FILTER_TYPE_DEFAULT);

  png_write_info(pngp, infop);

  // Initiallizing the point that will be used for populating the mesh values.
  // Initializing x, y, z to zero so that we don't access the point before it's
  // been set.  z = 0 for all the png's.
  Point pt(0, 0, 0);

  // Dense vector that we can pass into the _mesh_function to fill with a value for a given point.
  DenseVector<Number> dv(0);

  // Loop through to create the image.
  for (Real y = max_point(1); y >= min_point(1); y -= 1. / normalized_resolution)
  {
    pt(1) = y;
    unsigned int index = 0;
    for (Real x = min_point(0); x <= max_point(0); x += 1. / normalized_resolution)
    {
      pt(0) = x;
      (*_mesh_function)(pt, _time, dv, nullptr);

      // Determine whether to create the PNG in color or grayscale
      if (_color)
        setRGB(&row.data()[index * 4], applyScale(dv(0)));
      else
        row.data()[index] = applyScale(dv(0)) * 255;

      index++;
    }
    png_write_row(pngp, row.data());
  }

  // Close the file and take care of some other png end stuff.
  png_write_end(pngp, nullptr);
  if (fp != nullptr)
    fclose(fp);
  if (infop != nullptr)
    png_free_data(pngp, infop, PNG_FREE_ALL, -1);
  if (pngp != nullptr)
    png_destroy_write_struct(&pngp, &infop);
}

#endif
<|endoftext|>


<commit_before>// For conditions of distribution and use, see copyright notice in license.txt

#include "StableHeaders.h"
#include "QtUiAsset.h"
#include "AssetAPI.h"

#include <QByteArrayMatcher>
#include <QUrl>

#include "LoggingFunctions.h"
DEFINE_POCO_LOGGING_FUNCTIONS("QtUiAsset")

QtUiAsset::QtUiAsset(AssetAPI *owner, const QString &type_, const QString &name_) :
    IAsset(owner, type_, name_)
{
    patterns_ << "http://" << "https://" << "local://" << "file://";
    invalid_ref_chars_ << " " << "\n" << "\r" << "\t" << "\v" << "\f" << "\a";
}

QtUiAsset::~QtUiAsset()
{
}

bool QtUiAsset::DeserializeFromData(const u8 *data, size_t numBytes)
{
    refs_.clear();
    data_.clear();
    data_.insert(data_.begin(), data, data + numBytes);

    // If we are in headless mode, do not mark refs as dependency as it will
    // just spawn unneeded resources to the asset api without the actual need for them.
    // Note that this means we assume you will not show any ui on a headless run, while you
    // still could without the main window.
    if (assetAPI->IsHeadless())
        return true;

    // Find references
    QByteArray dataQt((const char*)&data_[0], data_.size());
    if (!dataQt.isNull() && !dataQt.isEmpty())
    {
        QByteArrayMatcher matcher;
        foreach(QByteArray pattern, patterns_)
        {
            int from = 0;
            int indexStart = 0;
            matcher.setPattern(pattern);
            while (indexStart != -1)
            {
                indexStart = matcher.indexIn(dataQt, from);
                if (indexStart == -1)
                    break;

                // ")" due to Qt style sheets have this syntax for example:
                // some-image-property: url({"|'}pattern{"|'});
                int indexStop1 = dataQt.indexOf(")", indexStart);
                // "<" due to normal qt xml defining images, for example:
                // <iconset><normaloff>pattern</normaloff>pattern</iconset>
                int indexStop2 = dataQt.indexOf("<", indexStart);
                if (indexStop1 == -1 && indexStop2 == -1)
                {
                    from = indexStart + 1;
                    continue;
                }
                int indexStop = indexStop1;
                if (indexStop2 < indexStop || indexStop == -1)
                    indexStop = indexStop2;
                from = indexStop;
                if (indexStop < indexStart)
                    continue;

                // Asset reference validation
                QString stringRef = dataQt.mid(indexStart, indexStop - indexStart).trimmed();

                // Ignore ui elements that have patterns as text, for example:
                // <widget><property name="text"><string>pattern</string></property></widget>
                if (indexStop == indexStop2)
                {
                    int indexStop3 = dataQt.indexOf(">", indexStart);
                    QString xmlEndTag = dataQt.mid(indexStop2, (indexStop3 - indexStop2) + 1);
                    if (xmlEndTag.toLower() == "</string>")
                        continue;
                }

                // Remove the last ' or " from url({"|'}pattern{"|'}) before the found )
                QChar lastChar = stringRef.at(stringRef.length()-1);
                if (lastChar == '\'' || lastChar == '\"')
                    stringRef.chop(1);
                if (stringRef.isEmpty() || stringRef.isNull())
                    continue;

                // Check for not wanted characters
                foreach(QString invalid, invalid_ref_chars_)
                    if (stringRef.contains(invalid))
                        continue;

                // QUrl validation, in tolerant mode
                QUrl ref(stringRef, QUrl::TolerantMode);
                if (!ref.isValid())
                    continue;

                // Seems legit, add it
                refs_.push_back(AssetReference(ref.toString()));
            }
        }
    }
    else
        LogError("FindReferences: Could not process .ui file content, error: data was null.");

    return true;
}

bool QtUiAsset::SerializeTo(std::vector<u8> &data, const QString &serializationParameters )
{
    if (data_.empty())
        return false;
    data.clear();
    data = data_;
    return true;
}

void QtUiAsset::DoUnload()
{
}

std::vector<AssetReference> QtUiAsset::FindReferences() const
{
    return refs_;
}

int QtUiAsset::ReplaceAssetReferences(QByteArray &uiData)
{
    int replacedRefs = 0;
    for(uint i=0; i<refs_.size(); ++i)
    {
        QString assetRef = refs_[i].ref;
        AssetPtr asset = assetAPI->GetAsset(assetRef);
        if (!asset.get())
        {
            LogError("ReplaceAssetReferences: Asset not found from asset system even when it was marked as a dependency earlier, skipping: " + assetRef.toStdString());
            continue;
        }
        QString refDiskSource = asset->DiskSource();
        if (refDiskSource.isEmpty())
        {
            LogWarning("ReplaceAssetReferences: Asset disk source empty, skipping: " + assetRef.toStdString());
            continue;
        }
        if (!QFile::exists(refDiskSource))
        {
            LogWarning("ReplaceAssetReferences: Asset disk source does not exist, skipping: " + assetRef.toStdString());
            continue;
        }
        uiData.replace(assetRef, refDiskSource.toStdString().c_str());
        replacedRefs++;
    }
    return replacedRefs;
}

bool QtUiAsset::IsDataValid() const
{
    return !data_.empty();
}

QByteArray QtUiAsset::GetRawData() const
{
    QByteArray returnData;
    if (!IsDataValid())
        return returnData;
    returnData = QByteArray((const char*)&data_[0], data_.size());
    return returnData;
}
<commit_msg>QtUiAsset: Added duplicate checks also for .ui parsed asset depepndency refs.<commit_after>// For conditions of distribution and use, see copyright notice in license.txt

#include "StableHeaders.h"
#include "QtUiAsset.h"
#include "AssetAPI.h"

#include <QByteArrayMatcher>
#include <QUrl>

#include "LoggingFunctions.h"
DEFINE_POCO_LOGGING_FUNCTIONS("QtUiAsset")

QtUiAsset::QtUiAsset(AssetAPI *owner, const QString &type_, const QString &name_) :
    IAsset(owner, type_, name_)
{
    patterns_ << "http://" << "https://" << "local://" << "file://";
    invalid_ref_chars_ << " " << "\n" << "\r" << "\t" << "\v" << "\f" << "\a";
}

QtUiAsset::~QtUiAsset()
{
}

bool QtUiAsset::DeserializeFromData(const u8 *data, size_t numBytes)
{
    refs_.clear();
    data_.clear();
    data_.insert(data_.begin(), data, data + numBytes);

    // If we are in headless mode, do not mark refs as dependency as it will
    // just spawn unneeded resources to the asset api without the actual need for them.
    // Note that this means we assume you will not show any ui on a headless run, while you
    // still could without the main window.
    if (assetAPI->IsHeadless())
        return true;

    // Find references
    QByteArray dataQt((const char*)&data_[0], data_.size());
    if (!dataQt.isNull() && !dataQt.isEmpty())
    {
        QByteArrayMatcher matcher;
        foreach(QByteArray pattern, patterns_)
        {
            int from = 0;
            int indexStart = 0;
            matcher.setPattern(pattern);
            while (indexStart != -1)
            {
                indexStart = matcher.indexIn(dataQt, from);
                if (indexStart == -1)
                    break;

                // ")" due to Qt style sheets have this syntax for example:
                // some-image-property: url({"|'}pattern{"|'});
                int indexStop1 = dataQt.indexOf(")", indexStart);
                // "<" due to normal qt xml defining images, for example:
                // <iconset><normaloff>pattern</normaloff>pattern</iconset>
                int indexStop2 = dataQt.indexOf("<", indexStart);
                if (indexStop1 == -1 && indexStop2 == -1)
                {
                    from = indexStart + 1;
                    continue;
                }
                int indexStop = indexStop1;
                if (indexStop2 < indexStop || indexStop == -1)
                    indexStop = indexStop2;
                from = indexStop;
                if (indexStop < indexStart)
                    continue;

                // Asset reference validation
                QString stringRef = dataQt.mid(indexStart, indexStop - indexStart).trimmed();

                // Ignore ui elements that have patterns as text, for example:
                // <widget><property name="text"><string>pattern</string></property></widget>
                if (indexStop == indexStop2)
                {
                    int indexStop3 = dataQt.indexOf(">", indexStart);
                    QString xmlEndTag = dataQt.mid(indexStop2, (indexStop3 - indexStop2) + 1);
                    if (xmlEndTag.toLower() == "</string>")
                        continue;
                }

                // Remove the last ' or " from url({"|'}pattern{"|'}) before the found )
                QChar lastChar = stringRef.at(stringRef.length()-1);
                if (lastChar == '\'' || lastChar == '\"')
                    stringRef.chop(1);
                if (stringRef.isEmpty() || stringRef.isNull())
                    continue;

                // Check for not wanted characters
                foreach(QString invalid, invalid_ref_chars_)
                    if (stringRef.contains(invalid))
                        continue;

                // QUrl validation, in tolerant mode
                QUrl ref(stringRef, QUrl::TolerantMode);
                if (!ref.isValid())
                    continue;

                AssetReference refStruct(ref.toString());

                // Check for duplicates
                for(size_t i=0; i<refs_.size(); ++i)
                    if (refs_[i].ref == refStruct.ref)
                        continue;

                // Seems legit, add it
                refs_.push_back(refStruct);
            }
        }
    }
    else
        LogError("FindReferences: Could not process .ui file content, error: data was null.");

    return true;
}

bool QtUiAsset::SerializeTo(std::vector<u8> &data, const QString &serializationParameters )
{
    if (data_.empty())
        return false;
    data.clear();
    data = data_;
    return true;
}

void QtUiAsset::DoUnload()
{
}

std::vector<AssetReference> QtUiAsset::FindReferences() const
{
    return refs_;
}

int QtUiAsset::ReplaceAssetReferences(QByteArray &uiData)
{
    int replacedRefs = 0;
    for(uint i=0; i<refs_.size(); ++i)
    {
        QString assetRef = refs_[i].ref;
        AssetPtr asset = assetAPI->GetAsset(assetRef);
        if (!asset.get())
        {
            LogError("ReplaceAssetReferences: Asset not found from asset system even when it was marked as a dependency earlier, skipping: " + assetRef.toStdString());
            continue;
        }
        QString refDiskSource = asset->DiskSource();
        if (refDiskSource.isEmpty())
        {
            LogWarning("ReplaceAssetReferences: Asset disk source empty, skipping: " + assetRef.toStdString());
            continue;
        }
        if (!QFile::exists(refDiskSource))
        {
            LogWarning("ReplaceAssetReferences: Asset disk source does not exist, skipping: " + assetRef.toStdString());
            continue;
        }
        uiData.replace(assetRef, refDiskSource.toStdString().c_str());
        replacedRefs++;
    }
    return replacedRefs;
}

bool QtUiAsset::IsDataValid() const
{
    return !data_.empty();
}

QByteArray QtUiAsset::GetRawData() const
{
    QByteArray returnData;
    if (!IsDataValid())
        return returnData;
    returnData = QByteArray((const char*)&data_[0], data_.size());
    return returnData;
}
<|endoftext|>


<commit_before>/*******************************************************************************
* Copyright 2009-2015 Juan Francisco Crespo Galán
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* 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 "PySource.h"

#include "Exception.h"
#include "fx/Source.h"

#include <memory>

extern PyObject* AUDError;

static PyObject *
Source_new(PyTypeObject* type, PyObject* args, PyObject* kwds)
{
	SourceP* self = (SourceP*)type->tp_alloc(type, 0);

	if(self != nullptr)
	{
		float azimuth, elevation;
		if(!PyArg_ParseTuple(args, "ff:angles", &azimuth, &elevation))
			return nullptr;

		try
		{
			self->source = new std::shared_ptr<aud::Source>(new aud::Source(azimuth, elevation));
		}
		catch(aud::Exception& e)
		{
			Py_DECREF(self);
			PyErr_SetString(AUDError, e.what());
			return nullptr;
		}
	}

	return (PyObject *)self;
}

static void
Source_dealloc(SourceP* self)
{
	if(self->source)
		delete reinterpret_cast<std::shared_ptr<aud::Source>*>(self->source);
	Py_TYPE(self)->tp_free((PyObject *)self);
}

static PyMethodDef Source_methods[] = {
	{ nullptr }  /* Sentinel */
};

PyDoc_STRVAR(M_aud_Source_azimuth_doc,
	"The azimuth angle.");

static int
Source_set_azimuth(SourceP* self, PyObject* args, void* nothing)
{
	float azimuth;

	if(!PyArg_Parse(args, "f:azimuth", &azimuth))
		return -1;

	try
	{
		(*reinterpret_cast<std::shared_ptr<aud::Source>*>(self->source))->setAzimuth(azimuth);
		PyErr_SetString(AUDError, "Couldn't change the azimuth!");
	}
	catch(aud::Exception& e)
	{
		PyErr_SetString(AUDError, e.what());
	}

	return -1;
}

static PyObject *
Source_get_azimuth(SourceP* self, void* nothing)
{
	try
	{
		return Py_BuildValue("f", (*reinterpret_cast<std::shared_ptr<aud::Source>*>(self->source))->getAzimuth());
	}
	catch(aud::Exception& e)
	{
		PyErr_SetString(AUDError, e.what());
		return nullptr;
	}
}

PyDoc_STRVAR(M_aud_Source_elevation_doc,
	"The elevation angle.");

static int
Source_set_elevation(SourceP* self, PyObject* args, void* nothing)
{
	float elevation;

	if(!PyArg_Parse(args, "f:elevation", &elevation))
		return -1;

	try
	{
		(*reinterpret_cast<std::shared_ptr<aud::Source>*>(self->source))->setElevation(elevation);
		PyErr_SetString(AUDError, "Couldn't change the elevation!");
	}
	catch(aud::Exception& e)
	{
		PyErr_SetString(AUDError, e.what());
	}

	return -1;
}

static PyObject *
Source_get_elevation(SourceP* self, void* nothing)
{
	try
	{
		return Py_BuildValue("f", (*reinterpret_cast<std::shared_ptr<aud::Source>*>(self->source))->getElevation());
	}
	catch(aud::Exception& e)
	{
		PyErr_SetString(AUDError, e.what());
		return nullptr;
	}
}

PyDoc_STRVAR(M_aud_Source_distance_doc,
	"The distance value. 0 is min, 1 is max.");

static int
Source_set_distance(SourceP* self, PyObject* args, void* nothing)
{
	float distance;

	if(!PyArg_Parse(args, "f:distance", &distance))
		return -1;

	try
	{
		(*reinterpret_cast<std::shared_ptr<aud::Source>*>(self->source))->setDistance(distance);
		PyErr_SetString(AUDError, "Couldn't change the distance!");
	}
	catch(aud::Exception& e)
	{
		PyErr_SetString(AUDError, e.what());
	}

	return -1;
}

static PyObject *
Source_get_distance(SourceP* self, void* nothing)
{
	try
	{
		return Py_BuildValue("f", (*reinterpret_cast<std::shared_ptr<aud::Source>*>(self->source))->getDistance());
	}
	catch(aud::Exception& e)
	{
		PyErr_SetString(AUDError, e.what());
		return nullptr;
	}
}

static PyGetSetDef Source_properties[] = {
	{ (char*)"azimuth", (getter)Source_get_azimuth, (setter)Source_set_azimuth,
	M_aud_Source_azimuth_doc, nullptr },
	{ (char*)"elevation", (getter)Source_get_elevation, (setter)Source_set_elevation,
	M_aud_Source_elevation_doc, nullptr },
	{ (char*)"distance", (getter)Source_get_distance, (setter)Source_set_distance,
	M_aud_Source_distance_doc, nullptr },
	{ nullptr }  /* Sentinel */
};

PyDoc_STRVAR(M_aud_Source_doc,
	"The source object represents the source position of a binaural sound.");

PyTypeObject SourceType = {
	PyVarObject_HEAD_INIT(nullptr, 0)
	"aud.Source",							/* tp_name */
	sizeof(SourceP),						/* tp_basicsize */
	0,										/* tp_itemsize */
	(destructor)Source_dealloc,				/* tp_dealloc */
	0,										/* tp_print */
	0,										/* tp_getattr */
	0,										/* tp_setattr */
	0,										/* tp_reserved */
	0,										/* tp_repr */
	0,										/* tp_as_number */
	0,										/* tp_as_sequence */
	0,										/* tp_as_mapping */
	0,										/* tp_hash  */
	0,										/* tp_call */
	0,										/* tp_str */
	0,										/* tp_getattro */
	0,										/* tp_setattro */
	0,										/* tp_as_buffer */
	Py_TPFLAGS_DEFAULT,						/* tp_flags */
	M_aud_Source_doc,						/* tp_doc */
	0,										/* tp_traverse */
	0,										/* tp_clear */
	0,										/* tp_richcompare */
	0,										/* tp_weaklistoffset */
	0,										/* tp_iter */
	0,										/* tp_iternext */
	Source_methods,							/* tp_methods */
	0,										/* tp_members */
	0,										/* tp_getset */
	0,										/* tp_base */
	0,										/* tp_dict */
	0,										/* tp_descr_get */
	0,										/* tp_descr_set */
	0,										/* tp_dictoffset */
	0,										/* tp_init */
	0,										/* tp_alloc */
	Source_new,								/* tp_new */
};

AUD_API PyObject* Source_empty()
{
	return SourceType.tp_alloc(&SourceType, 0);
}

AUD_API SourceP* checkSource(PyObject* source)
{
	if(!PyObject_TypeCheck(source, &SourceType))
	{
		PyErr_SetString(PyExc_TypeError, "Object is not of type Source!");
		return nullptr;
	}

	return (SourceP*)source;
}

bool initializeSource()
{
	return PyType_Ready(&SourceType) >= 0;
}

void addSourceToModule(PyObject* module)
{
	Py_INCREF(&SourceType);
	PyModule_AddObject(module, "Source", (PyObject *)&SourceType);
}
<commit_msg>Added distance to the Source constructos.<commit_after>/*******************************************************************************
* Copyright 2009-2015 Juan Francisco Crespo Galán
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* 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 "PySource.h"

#include "Exception.h"
#include "fx/Source.h"

#include <memory>

extern PyObject* AUDError;

static PyObject *
Source_new(PyTypeObject* type, PyObject* args, PyObject* kwds)
{
	SourceP* self = (SourceP*)type->tp_alloc(type, 0);

	if(self != nullptr)
	{
		float azimuth, elevation, distance;
		if(!PyArg_ParseTuple(args, "fff:angles", &azimuth, &elevation, &distance))
			return nullptr;

		try
		{
			self->source = new std::shared_ptr<aud::Source>(new aud::Source(azimuth, elevation, distance));
		}
		catch(aud::Exception& e)
		{
			Py_DECREF(self);
			PyErr_SetString(AUDError, e.what());
			return nullptr;
		}
	}

	return (PyObject *)self;
}

static void
Source_dealloc(SourceP* self)
{
	if(self->source)
		delete reinterpret_cast<std::shared_ptr<aud::Source>*>(self->source);
	Py_TYPE(self)->tp_free((PyObject *)self);
}

static PyMethodDef Source_methods[] = {
	{ nullptr }  /* Sentinel */
};

PyDoc_STRVAR(M_aud_Source_azimuth_doc,
	"The azimuth angle.");

static int
Source_set_azimuth(SourceP* self, PyObject* args, void* nothing)
{
	float azimuth;

	if(!PyArg_Parse(args, "f:azimuth", &azimuth))
		return -1;

	try
	{
		(*reinterpret_cast<std::shared_ptr<aud::Source>*>(self->source))->setAzimuth(azimuth);
		PyErr_SetString(AUDError, "Couldn't change the azimuth!");
	}
	catch(aud::Exception& e)
	{
		PyErr_SetString(AUDError, e.what());
	}

	return -1;
}

static PyObject *
Source_get_azimuth(SourceP* self, void* nothing)
{
	try
	{
		return Py_BuildValue("f", (*reinterpret_cast<std::shared_ptr<aud::Source>*>(self->source))->getAzimuth());
	}
	catch(aud::Exception& e)
	{
		PyErr_SetString(AUDError, e.what());
		return nullptr;
	}
}

PyDoc_STRVAR(M_aud_Source_elevation_doc,
	"The elevation angle.");

static int
Source_set_elevation(SourceP* self, PyObject* args, void* nothing)
{
	float elevation;

	if(!PyArg_Parse(args, "f:elevation", &elevation))
		return -1;

	try
	{
		(*reinterpret_cast<std::shared_ptr<aud::Source>*>(self->source))->setElevation(elevation);
		PyErr_SetString(AUDError, "Couldn't change the elevation!");
	}
	catch(aud::Exception& e)
	{
		PyErr_SetString(AUDError, e.what());
	}

	return -1;
}

static PyObject *
Source_get_elevation(SourceP* self, void* nothing)
{
	try
	{
		return Py_BuildValue("f", (*reinterpret_cast<std::shared_ptr<aud::Source>*>(self->source))->getElevation());
	}
	catch(aud::Exception& e)
	{
		PyErr_SetString(AUDError, e.what());
		return nullptr;
	}
}

PyDoc_STRVAR(M_aud_Source_distance_doc,
	"The distance value. 0 is min, 1 is max.");

static int
Source_set_distance(SourceP* self, PyObject* args, void* nothing)
{
	float distance;

	if(!PyArg_Parse(args, "f:distance", &distance))
		return -1;

	try
	{
		(*reinterpret_cast<std::shared_ptr<aud::Source>*>(self->source))->setDistance(distance);
		PyErr_SetString(AUDError, "Couldn't change the distance!");
	}
	catch(aud::Exception& e)
	{
		PyErr_SetString(AUDError, e.what());
	}

	return -1;
}

static PyObject *
Source_get_distance(SourceP* self, void* nothing)
{
	try
	{
		return Py_BuildValue("f", (*reinterpret_cast<std::shared_ptr<aud::Source>*>(self->source))->getDistance());
	}
	catch(aud::Exception& e)
	{
		PyErr_SetString(AUDError, e.what());
		return nullptr;
	}
}

static PyGetSetDef Source_properties[] = {
	{ (char*)"azimuth", (getter)Source_get_azimuth, (setter)Source_set_azimuth,
	M_aud_Source_azimuth_doc, nullptr },
	{ (char*)"elevation", (getter)Source_get_elevation, (setter)Source_set_elevation,
	M_aud_Source_elevation_doc, nullptr },
	{ (char*)"distance", (getter)Source_get_distance, (setter)Source_set_distance,
	M_aud_Source_distance_doc, nullptr },
	{ nullptr }  /* Sentinel */
};

PyDoc_STRVAR(M_aud_Source_doc,
	"The source object represents the source position of a binaural sound.");

PyTypeObject SourceType = {
	PyVarObject_HEAD_INIT(nullptr, 0)
	"aud.Source",							/* tp_name */
	sizeof(SourceP),						/* tp_basicsize */
	0,										/* tp_itemsize */
	(destructor)Source_dealloc,				/* tp_dealloc */
	0,										/* tp_print */
	0,										/* tp_getattr */
	0,										/* tp_setattr */
	0,										/* tp_reserved */
	0,										/* tp_repr */
	0,										/* tp_as_number */
	0,										/* tp_as_sequence */
	0,										/* tp_as_mapping */
	0,										/* tp_hash  */
	0,										/* tp_call */
	0,										/* tp_str */
	0,										/* tp_getattro */
	0,										/* tp_setattro */
	0,										/* tp_as_buffer */
	Py_TPFLAGS_DEFAULT,						/* tp_flags */
	M_aud_Source_doc,						/* tp_doc */
	0,										/* tp_traverse */
	0,										/* tp_clear */
	0,										/* tp_richcompare */
	0,										/* tp_weaklistoffset */
	0,										/* tp_iter */
	0,										/* tp_iternext */
	Source_methods,							/* tp_methods */
	0,										/* tp_members */
	0,										/* tp_getset */
	0,										/* tp_base */
	0,										/* tp_dict */
	0,										/* tp_descr_get */
	0,										/* tp_descr_set */
	0,										/* tp_dictoffset */
	0,										/* tp_init */
	0,										/* tp_alloc */
	Source_new,								/* tp_new */
};

AUD_API PyObject* Source_empty()
{
	return SourceType.tp_alloc(&SourceType, 0);
}

AUD_API SourceP* checkSource(PyObject* source)
{
	if(!PyObject_TypeCheck(source, &SourceType))
	{
		PyErr_SetString(PyExc_TypeError, "Object is not of type Source!");
		return nullptr;
	}

	return (SourceP*)source;
}

bool initializeSource()
{
	return PyType_Ready(&SourceType) >= 0;
}

void addSourceToModule(PyObject* module)
{
	Py_INCREF(&SourceType);
	PyModule_AddObject(module, "Source", (PyObject *)&SourceType);
}
<|endoftext|>


<commit_before>#ifndef MIMOSA_CONTAINER_CACHE_HH
# define MIMOSA_CONTAINER_CACHE_HH

# include <memory>
# include <unordered_map>

# include "../runtime/time.hh"
# include "../runtime/thread.hh"
# include "../sync/rwlock.hh"
# include "../sync/future.hh"

namespace mimosa
{
  namespace container
  {
    template <typename Key,
              typename Value,
              typename Hash = std::hash<Key>,
              typename KeyEqual = std::equal_to<Key> >
    class Cache
    {
    public:
      Cache();
      ~Cache();

      typename sync::Future<Value>::Ptr get(const Key & key);

      /// sets the duration after which an unsuded entry must be discarded
      void setEntryTimeout(runtime::Time time);

      /// sets the duration after which the value must be discarded
      void setValueTimeout(runtime::Time time);

      /// sets the cleanup period
      void setCleanupPeriod(runtime::Time time);

      /// starts the cleanup thread
      void startCleanupThread();

      /// stops the cleanup thread
      void stopCleanupThread();

      /// removes the specific key from the cache
      void remove(const Key & key);
      /// cleans up old cache entries
      void cleanup();
      /// removes every entries from the cache and cancels fetchs
      void clear();

    protected:

      class Entry
      {
      public:
        runtime::Time value_ts_;
        runtime::Time last_used_ts_;
        Value         value_;
      };

      typedef std::unordered_map<Key, Entry, Hash, KeyEqual> cache_type;
      typedef std::unordered_map<Key, typename sync::Future<Value>::Ptr, Hash, KeyEqual> fetch_type;

      void set(const Key & key, const Value & value);
      virtual void cacheMiss(const Key & key) = 0;
      void cleanupLoop();

      runtime::Time entry_timeout_;
      runtime::Time value_timeout_;
      runtime::Time cleanup_period_;

      sync::RWLock lock_;

      bool                             cleanup_thread_stop_;
      std::unique_ptr<runtime::Thread> cleanup_thread_;
      sync::Mutex                      cleanup_mutex_;
      sync::Condition                  cleanup_cond_;

      cache_type cache_;
      fetch_type fetch_;
    };
  }
}

#endif /* !MIMOSA_CONTAINER_CACHE_HH */
<commit_msg>cache: non copyable<commit_after>#ifndef MIMOSA_CONTAINER_CACHE_HH
# define MIMOSA_CONTAINER_CACHE_HH

# include <memory>
# include <unordered_map>

# include "../runtime/time.hh"
# include "../runtime/thread.hh"
# include "../sync/rwlock.hh"
# include "../sync/future.hh"

namespace mimosa
{
  namespace container
  {
    template <typename Key,
              typename Value,
              typename Hash = std::hash<Key>,
              typename KeyEqual = std::equal_to<Key> >
    class Cache : private NonCopyable
    {
    public:
      Cache();
      ~Cache();

      typename sync::Future<Value>::Ptr get(const Key & key);

      /// sets the duration after which an unsuded entry must be discarded
      void setEntryTimeout(runtime::Time time);

      /// sets the duration after which the value must be discarded
      void setValueTimeout(runtime::Time time);

      /// sets the cleanup period
      void setCleanupPeriod(runtime::Time time);

      /// starts the cleanup thread
      void startCleanupThread();

      /// stops the cleanup thread
      void stopCleanupThread();

      /// removes the specific key from the cache
      void remove(const Key & key);
      /// cleans up old cache entries
      void cleanup();
      /// removes every entries from the cache and cancels fetchs
      void clear();

    protected:

      class Entry
      {
      public:
        runtime::Time value_ts_;
        runtime::Time last_used_ts_;
        Value         value_;
      };

      typedef std::unordered_map<Key, Entry, Hash, KeyEqual> cache_type;
      typedef std::unordered_map<Key, typename sync::Future<Value>::Ptr, Hash, KeyEqual> fetch_type;

      void set(const Key & key, const Value & value);
      virtual void cacheMiss(const Key & key) = 0;
      void cleanupLoop();

      runtime::Time entry_timeout_;
      runtime::Time value_timeout_;
      runtime::Time cleanup_period_;

      sync::RWLock lock_;

      bool                             cleanup_thread_stop_;
      std::unique_ptr<runtime::Thread> cleanup_thread_;
      sync::Mutex                      cleanup_mutex_;
      sync::Condition                  cleanup_cond_;

      cache_type cache_;
      fetch_type fetch_;
    };
  }
}

#endif /* !MIMOSA_CONTAINER_CACHE_HH */
<|endoftext|>


<commit_before>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_GDT_SPACES_CONTINUOUSLAGRANGE_PDELAB_HH
#define DUNE_GDT_SPACES_CONTINUOUSLAGRANGE_PDELAB_HH

#include <memory>

#include <dune/common/typetraits.hh>
#include <dune/common/fvector.hh>
#include <dune/stuff/common/disable_warnings.hh>
# include <dune/common/parallel/communicator.hh>
#include <dune/stuff/common/reenable_warnings.hh>

#include <dune/geometry/genericgeometry/topologytypes.hh>

#include <dune/grid/common/capabilities.hh>

#if HAVE_DUNE_ISTL
# include <dune/stuff/common/disable_warnings.hh>
#   include <dune/istl/owneroverlapcopy.hh>
# include <dune/stuff/common/reenable_warnings.hh>
#endif

#if HAVE_DUNE_PDELAB
# include <dune/stuff/common/disable_warnings.hh>
#   include <dune/pdelab/finiteelementmap/pkfem.hh>
#   include <dune/pdelab/finiteelementmap/qkfem.hh>
#   include <dune/pdelab/gridfunctionspace/gridfunctionspace.hh>
#   include <dune/pdelab/constraints/conforming.hh>
#   include <dune/pdelab/backend/istl/parallelhelper.hh>
# include <dune/stuff/common/reenable_warnings.hh>
#endif // HAVE_DUNE_PDELAB

#include <dune/stuff/la/container/istl.hh>

#include "../../mapper/pdelab.hh"
#include "../../basefunctionset/pdelab.hh"

#include "base.hh"

namespace Dune {
namespace GDT {
namespace Spaces {
namespace ContinuousLagrange {

#if HAVE_DUNE_PDELAB

// forward, to be used in the traits and to allow for specialization
template< class GridViewImp, int polynomialOrder, class RangeFieldImp, int rangeDim, int rangeDimCols = 1 >
class PdelabBased
{
  static_assert((Dune::AlwaysFalse< GridViewImp >::value), "Untested for this combination of dimensions!");
};

template< class GridViewImp, int polynomialOrder, class RangeFieldImp, int rangeDim, int rangeDimCols = 1 >
class PdelabBasedTraits
{
public:
  typedef PdelabBased< GridViewImp, polynomialOrder, RangeFieldImp, rangeDim, rangeDimCols > derived_type;
  typedef GridViewImp                   GridViewType;
  static const int                      polOrder = polynomialOrder;
  static_assert(polOrder >= 1, "Wrong polOrder given!");
private:
  typedef typename GridViewType::ctype  DomainFieldType;
public:
  static const unsigned int             dimDomain = GridViewType::dimension;
  typedef RangeFieldImp                 RangeFieldType;
  static const unsigned int             dimRange = rangeDim;
  static const unsigned int             dimRangeCols = rangeDimCols;
private:
  template< class G, bool single_geom, bool is_simplex, bool is_cube >
  struct FeMap
  {
    static_assert(Dune::AlwaysFalse< G >::value,
                  "This space is only implemented for either fully simplicial or fully cubic grids!");
  };
  template< class G >
  struct FeMap< G, true, true, false >
  {
    typedef PDELab::PkLocalFiniteElementMap < GridViewType, DomainFieldType, RangeFieldType, polOrder> Type;
  };
  template< class G >
  struct FeMap< G, true, false, true >
  {
    typedef PDELab::QkLocalFiniteElementMap < GridViewType, DomainFieldType, RangeFieldType, polOrder> Type;
  };
  typedef typename GridViewType::Grid GridType;
  static const bool single_geom_ = Dune::Capabilities::hasSingleGeometryType< GridType >::v;
  static const bool simplicial_ = (Dune::Capabilities::hasSingleGeometryType< GridType >::topologyId
                                   == GenericGeometry::SimplexTopology< dimDomain >::type::id);
  static const bool cubic_ = (Dune::Capabilities::hasSingleGeometryType< GridType >::topologyId
                              == GenericGeometry::CubeTopology< dimDomain >::type::id);
  typedef typename FeMap< GridType, single_geom_, simplicial_, cubic_ >::Type FEMapType;
public:
  typedef PDELab::GridFunctionSpace< GridViewType, FEMapType, PDELab::OverlappingConformingDirichletConstraints > BackendType;
  typedef Mapper::SimplePdelabWrapper< BackendType > MapperType;
  typedef typename GridViewType::template Codim< 0 >::Entity EntityType;
  typedef BaseFunctionSet::PdelabWrapper
      < BackendType, EntityType, DomainFieldType, dimDomain, RangeFieldType, dimRange, dimRangeCols >
    BaseFunctionSetType;
  static const Stuff::Grid::ChoosePartView part_view_type = Stuff::Grid::ChoosePartView::view;
  static const bool needs_grid_view = true;
#if HAVE_MPI && HAVE_DUNE_ISTL
  typedef OwnerOverlapCopyCommunication< bigunsignedint< 96 >, int > CommunicatorType;
#else
  typedef double CommunicatorType;
#endif
private:
  friend class PdelabBased< GridViewImp, polynomialOrder, RangeFieldImp, rangeDim, rangeDimCols >;
}; // class SpaceWrappedFemContinuousLagrangeTraits

template< class GridViewImp, int polynomialOrder, class RangeFieldImp >
class PdelabBased< GridViewImp, polynomialOrder, RangeFieldImp, 1, 1 >
  : public Spaces::ContinuousLagrangeBase< PdelabBasedTraits< GridViewImp, polynomialOrder, RangeFieldImp, 1, 1 >
                                      , GridViewImp::dimension, RangeFieldImp, 1, 1 >
{
  typedef Spaces::ContinuousLagrangeBase< PdelabBasedTraits< GridViewImp, polynomialOrder, RangeFieldImp, 1, 1 >
                                     , GridViewImp::dimension, RangeFieldImp, 1, 1 >  BaseType;
  typedef PdelabBased< GridViewImp, polynomialOrder, RangeFieldImp, 1, 1 >          ThisType;
public:
  typedef PdelabBasedTraits< GridViewImp, polynomialOrder, RangeFieldImp, 1, 1 > Traits;

  typedef typename Traits::GridViewType GridViewType;
  static const int                      polOrder = Traits::polOrder;
  typedef typename GridViewType::ctype  DomainFieldType;
  static const unsigned int             dimDomain = GridViewType::dimension;
  typedef FieldVector< DomainFieldType, dimDomain > DomainType;
  typedef typename Traits::RangeFieldType RangeFieldType;
  static const unsigned int               dimRange = Traits::dimRange;
  static const unsigned int               dimRangeCols = Traits::dimRangeCols;

  typedef typename Traits::BackendType          BackendType;
  typedef typename Traits::MapperType           MapperType;
  typedef typename Traits::BaseFunctionSetType  BaseFunctionSetType;
  typedef typename Traits::CommunicatorType     CommunicatorType;

private:
  typedef typename Traits::FEMapType FEMapType;
#if HAVE_MPI && HAVE_DUNE_ISTL
  typedef PDELab::istl::ParallelHelper< BackendType > ParallelHelperType;
#endif

public:
  typedef typename BaseType::IntersectionType  IntersectionType;
  typedef typename BaseType::EntityType        EntityType;
  typedef typename BaseType::PatternType       PatternType;
  typedef typename BaseType::BoundaryInfoType  BoundaryInfoType;

  PdelabBased(const std::shared_ptr< const GridViewType >& gV)
    : gridView_(gV)
    , fe_map_(std::make_shared< FEMapType >(*(gridView_)))
    , backend_(std::make_shared< BackendType >(const_cast< GridViewType& >(*gridView_), *fe_map_))
    , mapper_(std::make_shared< MapperType >(*backend_))
#if HAVE_MPI && HAVE_DUNE_ISTL
    , parallel_helper_(std::make_shared< ParallelHelperType >(*backend_, 0))
    , communicator_(std::make_shared< CommunicatorType >(gridView_->comm()))
    , communicator_prepared_(false)
#else // HAVE_MPI && HAVE_DUNE_ISTL
    , communicator_(0.0)
#endif // HAVE_MPI && HAVE_DUNE_ISTL
  {}

  PdelabBased(const ThisType& other)
    : gridView_(other.gridView_)
    , fe_map_(other.fe_map_)
    , backend_(other.backend_)
    , mapper_(other.mapper_)
#if HAVE_MPI && HAVE_DUNE_ISTL
    , parallel_helper_(other.parallel_helper_)
    , communicator_(other.communicator_)
    , communicator_prepared_(other.communicator_prepared_)
#else // HAVE_MPI && HAVE_DUNE_ISTL
    , communicator_(other.communicator_)
#endif // HAVE_MPI && HAVE_DUNE_ISTL
  {}

  ThisType& operator=(const ThisType& other)
  {
    if (this != &other) {
      gridView_ = other.gridView_;
      fe_map_ = other.fe_map_;
      backend_ = other.backend_;
      mapper_ = other.mapper_;
#if HAVE_MPI && HAVE_DUNE_ISTL
      parallel_helper_ = other.parallel_helper_;
      communicator_ = other.communicator_;
      communicator_prepared_ = other.communicator_prepared_;
#else // HAVE_MPI && HAVE_DUNE_ISTL
      communicator_ = other.communicator_;
#endif // HAVE_MPI && HAVE_DUNE_ISTL
    }
    return *this;
  }

  ~PdelabBased() {}

  const std::shared_ptr< const GridViewType >& grid_view() const
  {
    return gridView_;
  }

  const BackendType& backend() const
  {
    return *backend_;
  }

  const MapperType& mapper() const
  {
    return *mapper_;
  }

  BaseFunctionSetType base_function_set(const EntityType& entity) const
  {
    return BaseFunctionSetType(*backend_, entity);
  }

#if HAVE_MPI && HAVE_DUNE_ISTL
  CommunicatorType& communicator() const
  {
    if (!communicator_prepared_) {
      Stuff::LA::IstlRowMajorSparseMatrix< RangeFieldType > istl_matrix;
      parallel_helper_->createIndexSetAndProjectForAMG(istl_matrix.backend() , *communicator_);
      communicator_prepared_ = true;
    }
    return *communicator_;
  } // ... communicator(...)
#else // HAVE_MPI && HAVE_DUNE_ISTL
  CommunicatorType& communicator() const
  {
    return communicator_;
  }
#endif // HAVE_MPI && HAVE_DUNE_ISTL

private:
  std::shared_ptr< const GridViewType > gridView_;
  std::shared_ptr< const FEMapType > fe_map_;
  std::shared_ptr< const BackendType > backend_;
  std::shared_ptr< const MapperType > mapper_;
#if HAVE_MPI && HAVE_DUNE_ISTL
  mutable std::shared_ptr< ParallelHelperType > parallel_helper_;
  mutable std::shared_ptr< CommunicatorType > communicator_;
  mutable bool communicator_prepared_;
#else // HAVE_MPI && HAVE_DUNE_ISTL
  mutable double communicator_;
#endif // HAVE_MPI && HAVE_DUNE_ISTL
}; // class PdelabBased< ..., 1 >

#else // HAVE_DUNE_PDELAB

template< class GridViewImp, int polynomialOrder, class RangeFieldImp, int rangeDim, int rangeDimCols = 1 >
class PdelabBased
{
  static_assert((Dune::AlwaysFalse< GridViewImp >::value), "You are missing dune-pdelab!");
};

#endif // HAVE_DUNE_PDELAB

} // namespace ContinuousLagrange
} // namespace Spaces
} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_SPACES_CONTINUOUSLAGRANGE_PDELAB_HH
<commit_msg>[spaces.cg.pdelab] whitespace<commit_after>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_GDT_SPACES_CONTINUOUSLAGRANGE_PDELAB_HH
#define DUNE_GDT_SPACES_CONTINUOUSLAGRANGE_PDELAB_HH

#include <memory>

#include <dune/common/typetraits.hh>
#include <dune/common/fvector.hh>
#include <dune/stuff/common/disable_warnings.hh>
# include <dune/common/parallel/communicator.hh>
#include <dune/stuff/common/reenable_warnings.hh>

#include <dune/geometry/genericgeometry/topologytypes.hh>

#include <dune/grid/common/capabilities.hh>

#if HAVE_DUNE_ISTL
# include <dune/stuff/common/disable_warnings.hh>
#   include <dune/istl/owneroverlapcopy.hh>
# include <dune/stuff/common/reenable_warnings.hh>
#endif

#if HAVE_DUNE_PDELAB
# include <dune/stuff/common/disable_warnings.hh>
#   include <dune/pdelab/finiteelementmap/pkfem.hh>
#   include <dune/pdelab/finiteelementmap/qkfem.hh>
#   include <dune/pdelab/gridfunctionspace/gridfunctionspace.hh>
#   include <dune/pdelab/constraints/conforming.hh>
#   include <dune/pdelab/backend/istl/parallelhelper.hh>
# include <dune/stuff/common/reenable_warnings.hh>
#endif // HAVE_DUNE_PDELAB

#include <dune/stuff/la/container/istl.hh>

#include "../../mapper/pdelab.hh"
#include "../../basefunctionset/pdelab.hh"

#include "base.hh"

namespace Dune {
namespace GDT {
namespace Spaces {
namespace ContinuousLagrange {

#if HAVE_DUNE_PDELAB

// forward, to be used in the traits and to allow for specialization
template< class GridViewImp, int polynomialOrder, class RangeFieldImp, int rangeDim, int rangeDimCols = 1 >
class PdelabBased
{
  static_assert((Dune::AlwaysFalse< GridViewImp >::value), "Untested for this combination of dimensions!");
};

template< class GridViewImp, int polynomialOrder, class RangeFieldImp, int rangeDim, int rangeDimCols = 1 >
class PdelabBasedTraits
{
public:
  typedef PdelabBased< GridViewImp, polynomialOrder, RangeFieldImp, rangeDim, rangeDimCols > derived_type;
  typedef GridViewImp                   GridViewType;
  static const int                      polOrder = polynomialOrder;
  static_assert(polOrder >= 1, "Wrong polOrder given!");
private:
  typedef typename GridViewType::ctype  DomainFieldType;
public:
  static const unsigned int             dimDomain = GridViewType::dimension;
  typedef RangeFieldImp                 RangeFieldType;
  static const unsigned int             dimRange = rangeDim;
  static const unsigned int             dimRangeCols = rangeDimCols;
private:
  template< class G, bool single_geom, bool is_simplex, bool is_cube >
  struct FeMap
  {
    static_assert(Dune::AlwaysFalse< G >::value,
                  "This space is only implemented for either fully simplicial or fully cubic grids!");
  };
  template< class G >
  struct FeMap< G, true, true, false >
  {
    typedef PDELab::PkLocalFiniteElementMap < GridViewType, DomainFieldType, RangeFieldType, polOrder> Type;
  };
  template< class G >
  struct FeMap< G, true, false, true >
  {
    typedef PDELab::QkLocalFiniteElementMap < GridViewType, DomainFieldType, RangeFieldType, polOrder> Type;
  };
  typedef typename GridViewType::Grid GridType;
  static const bool single_geom_ = Dune::Capabilities::hasSingleGeometryType< GridType >::v;
  static const bool simplicial_ = (Dune::Capabilities::hasSingleGeometryType< GridType >::topologyId
                                   == GenericGeometry::SimplexTopology< dimDomain >::type::id);
  static const bool cubic_ = (Dune::Capabilities::hasSingleGeometryType< GridType >::topologyId
                              == GenericGeometry::CubeTopology< dimDomain >::type::id);
  typedef typename FeMap< GridType, single_geom_, simplicial_, cubic_ >::Type FEMapType;
public:
  typedef PDELab::GridFunctionSpace< GridViewType, FEMapType, PDELab::OverlappingConformingDirichletConstraints > BackendType;
  typedef Mapper::SimplePdelabWrapper< BackendType > MapperType;
  typedef typename GridViewType::template Codim< 0 >::Entity EntityType;
  typedef BaseFunctionSet::PdelabWrapper
      < BackendType, EntityType, DomainFieldType, dimDomain, RangeFieldType, dimRange, dimRangeCols >
    BaseFunctionSetType;
  static const Stuff::Grid::ChoosePartView part_view_type = Stuff::Grid::ChoosePartView::view;
  static const bool needs_grid_view = true;
#if HAVE_MPI && HAVE_DUNE_ISTL
  typedef OwnerOverlapCopyCommunication< bigunsignedint< 96 >, int > CommunicatorType;
#else
  typedef double CommunicatorType;
#endif
private:
  friend class PdelabBased< GridViewImp, polynomialOrder, RangeFieldImp, rangeDim, rangeDimCols >;
}; // class SpaceWrappedFemContinuousLagrangeTraits

template< class GridViewImp, int polynomialOrder, class RangeFieldImp >
class PdelabBased< GridViewImp, polynomialOrder, RangeFieldImp, 1, 1 >
  : public Spaces::ContinuousLagrangeBase< PdelabBasedTraits< GridViewImp, polynomialOrder, RangeFieldImp, 1, 1 >
                                      , GridViewImp::dimension, RangeFieldImp, 1, 1 >
{
  typedef Spaces::ContinuousLagrangeBase< PdelabBasedTraits< GridViewImp, polynomialOrder, RangeFieldImp, 1, 1 >
                                     , GridViewImp::dimension, RangeFieldImp, 1, 1 >  BaseType;
  typedef PdelabBased< GridViewImp, polynomialOrder, RangeFieldImp, 1, 1 >          ThisType;
public:
  typedef PdelabBasedTraits< GridViewImp, polynomialOrder, RangeFieldImp, 1, 1 > Traits;

  typedef typename Traits::GridViewType GridViewType;
  static const int                      polOrder = Traits::polOrder;
  typedef typename GridViewType::ctype  DomainFieldType;
  static const unsigned int             dimDomain = GridViewType::dimension;
  typedef FieldVector< DomainFieldType, dimDomain > DomainType;
  typedef typename Traits::RangeFieldType RangeFieldType;
  static const unsigned int               dimRange = Traits::dimRange;
  static const unsigned int               dimRangeCols = Traits::dimRangeCols;

  typedef typename Traits::BackendType          BackendType;
  typedef typename Traits::MapperType           MapperType;
  typedef typename Traits::BaseFunctionSetType  BaseFunctionSetType;
  typedef typename Traits::CommunicatorType     CommunicatorType;

private:
  typedef typename Traits::FEMapType FEMapType;
#if HAVE_MPI && HAVE_DUNE_ISTL
  typedef PDELab::istl::ParallelHelper< BackendType > ParallelHelperType;
#endif

public:
  typedef typename BaseType::IntersectionType  IntersectionType;
  typedef typename BaseType::EntityType        EntityType;
  typedef typename BaseType::PatternType       PatternType;
  typedef typename BaseType::BoundaryInfoType  BoundaryInfoType;

  PdelabBased(const std::shared_ptr< const GridViewType >& gV)
    : gridView_(gV)
    , fe_map_(std::make_shared< FEMapType >(*(gridView_)))
    , backend_(std::make_shared< BackendType >(const_cast< GridViewType& >(*gridView_), *fe_map_))
    , mapper_(std::make_shared< MapperType >(*backend_))
#if HAVE_MPI && HAVE_DUNE_ISTL
    , parallel_helper_(std::make_shared< ParallelHelperType >(*backend_, 0))
    , communicator_(std::make_shared< CommunicatorType >(gridView_->comm()))
    , communicator_prepared_(false)
#else // HAVE_MPI && HAVE_DUNE_ISTL
    , communicator_(0.0)
#endif
  {}

  PdelabBased(const ThisType& other)
    : gridView_(other.gridView_)
    , fe_map_(other.fe_map_)
    , backend_(other.backend_)
    , mapper_(other.mapper_)
#if HAVE_MPI && HAVE_DUNE_ISTL
    , parallel_helper_(other.parallel_helper_)
    , communicator_(other.communicator_)
    , communicator_prepared_(other.communicator_prepared_)
#else // HAVE_MPI && HAVE_DUNE_ISTL
    , communicator_(other.communicator_)
#endif // HAVE_MPI && HAVE_DUNE_ISTL
  {}

  ThisType& operator=(const ThisType& other)
  {
    if (this != &other) {
      gridView_ = other.gridView_;
      fe_map_ = other.fe_map_;
      backend_ = other.backend_;
      mapper_ = other.mapper_;
#if HAVE_MPI && HAVE_DUNE_ISTL
      parallel_helper_ = other.parallel_helper_;
      communicator_ = other.communicator_;
      communicator_prepared_ = other.communicator_prepared_;
#else // HAVE_MPI && HAVE_DUNE_ISTL
      communicator_ = other.communicator_;
#endif // HAVE_MPI && HAVE_DUNE_ISTL
    }
    return *this;
  }

  ~PdelabBased() {}

  const std::shared_ptr< const GridViewType >& grid_view() const
  {
    return gridView_;
  }

  const BackendType& backend() const
  {
    return *backend_;
  }

  const MapperType& mapper() const
  {
    return *mapper_;
  }

  BaseFunctionSetType base_function_set(const EntityType& entity) const
  {
    return BaseFunctionSetType(*backend_, entity);
  }

#if HAVE_MPI && HAVE_DUNE_ISTL
  CommunicatorType& communicator() const
  {
    if (!communicator_prepared_) {
      Stuff::LA::IstlRowMajorSparseMatrix< RangeFieldType > istl_matrix;
      parallel_helper_->createIndexSetAndProjectForAMG(istl_matrix.backend() , *communicator_);
      communicator_prepared_ = true;
    }
    return *communicator_;
  } // ... communicator(...)
#else // HAVE_MPI && HAVE_DUNE_ISTL
  CommunicatorType& communicator() const
  {
    return communicator_;
  }
#endif // HAVE_MPI && HAVE_DUNE_ISTL

private:
  std::shared_ptr< const GridViewType > gridView_;
  std::shared_ptr< const FEMapType > fe_map_;
  std::shared_ptr< const BackendType > backend_;
  std::shared_ptr< const MapperType > mapper_;
#if HAVE_MPI && HAVE_DUNE_ISTL
  mutable std::shared_ptr< ParallelHelperType > parallel_helper_;
  mutable std::shared_ptr< CommunicatorType > communicator_;
  mutable bool communicator_prepared_;
#else // HAVE_MPI && HAVE_DUNE_ISTL
  mutable double communicator_;
#endif // HAVE_MPI && HAVE_DUNE_ISTL
}; // class PdelabBased< ..., 1 >

#else // HAVE_DUNE_PDELAB

template< class GridViewImp, int polynomialOrder, class RangeFieldImp, int rangeDim, int rangeDimCols = 1 >
class PdelabBased
{
  static_assert((Dune::AlwaysFalse< GridViewImp >::value), "You are missing dune-pdelab!");
};

#endif // HAVE_DUNE_PDELAB

} // namespace ContinuousLagrange
} // namespace Spaces
} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_SPACES_CONTINUOUSLAGRANGE_PDELAB_HH
<|endoftext|>


<commit_before>//
//  Rigidbody.cpp
//  Vortex2D
//

#include "Rigidbody.h"
#include <Vortex2D/SPIRV/Reflection.h>
#include <Vortex2D/Renderer/CommandBuffer.h>
#include <Vortex2D/Engine/Boundaries.h>

#include "vortex2d_generated_spirv.h"

#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/transform.hpp>

namespace Vortex2D { namespace Fluid {

RigidBody::RigidBody(const Renderer::Device& device,
                     const glm::ivec2& size,
                     float delta,
                     Renderer::Drawable& drawable,
                     const glm::vec2& centre,
                     Renderer::RenderTexture& phi,
                     vk::Flags<Type> type,
                     float mass,
                     float inertia)
    : mSize(size.x)
    , mDelta(delta)
    , mDevice(device)
    , mPhi(device, size.x, size.y, vk::Format::eR32Sfloat)
    , mDrawable(drawable)
    , mCentre(centre)
    , mVelocity(device)
    , mForce(device, size.x * size.y)
    , mReducedForce(device, 1)
    , mLocalForce(device, 1, VMA_MEMORY_USAGE_GPU_TO_CPU)
    , mMVBuffer(device, VMA_MEMORY_USAGE_CPU_TO_GPU)
    , mLocalVelocity(device, VMA_MEMORY_USAGE_CPU_ONLY)
    , mClear({1000.0f, 0.0f, 0.0f, 0.0f})
    , mDiv(device, size, SPIRV::BuildRigidbodyDiv_comp)
    , mConstrain(device, size, SPIRV::ConstrainRigidbodyVelocity_comp)
    , mForceWork(device, size, SPIRV::RigidbodyForce_comp)
    , mPressureWork(device, size, SPIRV::RigidbodyPressure_comp)
    , mDivCmd(device, false)
    , mConstrainCmd(device, false)
    , mForceCmd(device, true)
    , mPressureCmd(device, false)
    , mVelocityCmd(device, false)
    , mSum(device, size)
    , mType(type)
    , mMass(mass)
    , mInertia(inertia)
{
    mLocalPhiRender = mPhi.Record({mClear, mDrawable}, UnionBlend);

    mVelocityCmd.Record([&](vk::CommandBuffer commandBuffer)
    {
        mVelocity.CopyFrom(commandBuffer, mLocalVelocity);
    });

    SetVelocities(glm::vec2(0.0f), 0.0f);

    mPhiRender = phi.Record({mDrawable}, UnionBlend);
}

void RigidBody::SetVelocities(const glm::vec2& velocity, float angularVelocity)
{
    Velocity v{velocity / glm::vec2(mSize), angularVelocity};

    Renderer::CopyFrom(mLocalVelocity, v);
    mVelocityCmd.Submit();
}

RigidBody::Velocity RigidBody::GetForces()
{
    mForceCmd.Wait();

    Velocity force;
    Renderer::CopyTo(mLocalForce, force);

    //force.velocity *= glm::vec2(mSize);
    //force.angular_velocity *= mSize * mSize;

    return force;
}

void RigidBody::UpdatePosition()
{
    Renderer::CopyFrom(mMVBuffer, glm::translate(glm::vec3{(glm::vec2)Position, 0.0f}));
}

void RigidBody::RenderPhi()
{
    mLocalPhiRender.Submit(GetTransform());
    mPhiRender.Submit(GetTransform());
}

void RigidBody::BindDiv(Renderer::GenericBuffer& div,
                        Renderer::GenericBuffer& diagonal)
{
    mDivBound = mDiv.Bind({div, diagonal , mPhi, mVelocity, mMVBuffer});
    mDivCmd.Record([&](vk::CommandBuffer commandBuffer)
    {
        commandBuffer.debugMarkerBeginEXT({"Rigidbody build equation", {{0.90f, 0.27f, 0.28f, 1.0f}}});
        mDivBound.PushConstant(commandBuffer, mCentre);
        mDivBound.Record(commandBuffer);
        div.Barrier(commandBuffer, vk::AccessFlagBits::eShaderWrite, vk::AccessFlagBits::eShaderRead);
        commandBuffer.debugMarkerEndEXT();
    });
}

void RigidBody::BindVelocityConstrain(Fluid::Velocity& velocity)
{
    mConstrainBound = mConstrain.Bind({velocity, velocity.Output(), mPhi, mVelocity, mMVBuffer});
    mConstrainCmd.Record([&](vk::CommandBuffer commandBuffer)
    {
        commandBuffer.debugMarkerBeginEXT({"Rigidbody constrain", {{0.29f, 0.36f, 0.21f, 1.0f}}});
        mConstrainBound.PushConstant(commandBuffer, mCentre);
        mConstrainBound.Record(commandBuffer);
        velocity.CopyBack(commandBuffer);
        commandBuffer.debugMarkerEndEXT();
    });
}

void RigidBody::BindForce(Renderer::GenericBuffer& diagonal,
                          Renderer::GenericBuffer& pressure)
{
    mForceBound = mForceWork.Bind({diagonal, mPhi, pressure, mForce, mMVBuffer});
    mLocalSumBound = mSum.Bind(mForce, mLocalForce);
    mForceCmd.Record([&](vk::CommandBuffer commandBuffer)
    {
        commandBuffer.debugMarkerBeginEXT({"Rigidbody force", {{0.70f, 0.59f, 0.63f, 1.0f}}});
        mForce.Clear(commandBuffer);
        mForceBound.PushConstant(commandBuffer, mCentre);
        mForceBound.Record(commandBuffer);
        mForce.Barrier(commandBuffer, vk::AccessFlagBits::eShaderWrite, vk::AccessFlagBits::eShaderRead);
        mLocalSumBound.Record(commandBuffer);
        commandBuffer.debugMarkerEndEXT();
    });
}

void RigidBody::BindPressure(Renderer::GenericBuffer& d,
                             Renderer::GenericBuffer& s,
                             Renderer::GenericBuffer& z)
{
    mPressureForceBound = mForceWork.Bind({d, mPhi, s, mForce, mMVBuffer});
    mPressureBound = mPressureWork.Bind({d, mPhi, mReducedForce, z, mMVBuffer});
    mSumBound = mSum.Bind(mForce, mReducedForce);
    mPressureCmd.Record([&](vk::CommandBuffer commandBuffer)
    {
        commandBuffer.debugMarkerBeginEXT({"Rigidbody pressure", {{0.70f, 0.59f, 0.63f, 1.0f}}});
        mForce.Clear(commandBuffer);
        mPressureForceBound.PushConstant(commandBuffer, mCentre);
        mPressureForceBound.Record(commandBuffer);
        mForce.Barrier(commandBuffer, vk::AccessFlagBits::eShaderWrite, vk::AccessFlagBits::eShaderRead);
        mSumBound.Record(commandBuffer);
        mPressureBound.PushConstant(commandBuffer, mCentre, mDelta, mMass, mInertia);
        mPressureBound.Record(commandBuffer);
        z.Barrier(commandBuffer, vk::AccessFlagBits::eShaderWrite, vk::AccessFlagBits::eShaderRead);
        commandBuffer.debugMarkerEndEXT();
    });
}

void RigidBody::Div()
{
    mDivCmd.Submit();
}

void RigidBody::Force()
{
    mForceCmd.Submit();
}

void RigidBody::Pressure()
{
    mPressureCmd.Submit();
}

void RigidBody::VelocityConstrain()
{
    mConstrainCmd.Submit();
}

vk::Flags<RigidBody::Type> RigidBody::GetType()
{
    return mType;
}

Renderer::RenderTexture& RigidBody::Phi()
{
    return mPhi;
}

}}
<commit_msg>set force scaling<commit_after>//
//  Rigidbody.cpp
//  Vortex2D
//

#include "Rigidbody.h"
#include <Vortex2D/SPIRV/Reflection.h>
#include <Vortex2D/Renderer/CommandBuffer.h>
#include <Vortex2D/Engine/Boundaries.h>

#include "vortex2d_generated_spirv.h"

#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/transform.hpp>

namespace Vortex2D { namespace Fluid {

RigidBody::RigidBody(const Renderer::Device& device,
                     const glm::ivec2& size,
                     float delta,
                     Renderer::Drawable& drawable,
                     const glm::vec2& centre,
                     Renderer::RenderTexture& phi,
                     vk::Flags<Type> type,
                     float mass,
                     float inertia)
    : mSize(size.x)
    , mDelta(delta)
    , mDevice(device)
    , mPhi(device, size.x, size.y, vk::Format::eR32Sfloat)
    , mDrawable(drawable)
    , mCentre(centre)
    , mVelocity(device)
    , mForce(device, size.x * size.y)
    , mReducedForce(device, 1)
    , mLocalForce(device, 1, VMA_MEMORY_USAGE_GPU_TO_CPU)
    , mMVBuffer(device, VMA_MEMORY_USAGE_CPU_TO_GPU)
    , mLocalVelocity(device, VMA_MEMORY_USAGE_CPU_ONLY)
    , mClear({1000.0f, 0.0f, 0.0f, 0.0f})
    , mDiv(device, size, SPIRV::BuildRigidbodyDiv_comp)
    , mConstrain(device, size, SPIRV::ConstrainRigidbodyVelocity_comp)
    , mForceWork(device, size, SPIRV::RigidbodyForce_comp)
    , mPressureWork(device, size, SPIRV::RigidbodyPressure_comp)
    , mDivCmd(device, false)
    , mConstrainCmd(device, false)
    , mForceCmd(device, true)
    , mPressureCmd(device, false)
    , mVelocityCmd(device, false)
    , mSum(device, size)
    , mType(type)
    , mMass(mass)
    , mInertia(inertia)
{
    mLocalPhiRender = mPhi.Record({mClear, mDrawable}, UnionBlend);

    mVelocityCmd.Record([&](vk::CommandBuffer commandBuffer)
    {
        mVelocity.CopyFrom(commandBuffer, mLocalVelocity);
    });

    SetVelocities(glm::vec2(0.0f), 0.0f);

    mPhiRender = phi.Record({mDrawable}, UnionBlend);
}

void RigidBody::SetVelocities(const glm::vec2& velocity, float angularVelocity)
{
    Velocity v{velocity / glm::vec2(mSize), angularVelocity};

    Renderer::CopyFrom(mLocalVelocity, v);
    mVelocityCmd.Submit();
}

RigidBody::Velocity RigidBody::GetForces()
{
    mForceCmd.Wait();

    Velocity force;
    Renderer::CopyTo(mLocalForce, force);

    force.velocity *= glm::vec2(mSize);
    force.angular_velocity *= mSize * mSize;

    return force;
}

void RigidBody::UpdatePosition()
{
    Renderer::CopyFrom(mMVBuffer, glm::translate(glm::vec3{(glm::vec2)Position, 0.0f}));
}

void RigidBody::RenderPhi()
{
    mLocalPhiRender.Submit(GetTransform());
    mPhiRender.Submit(GetTransform());
}

void RigidBody::BindDiv(Renderer::GenericBuffer& div,
                        Renderer::GenericBuffer& diagonal)
{
    mDivBound = mDiv.Bind({div, diagonal , mPhi, mVelocity, mMVBuffer});
    mDivCmd.Record([&](vk::CommandBuffer commandBuffer)
    {
        commandBuffer.debugMarkerBeginEXT({"Rigidbody build equation", {{0.90f, 0.27f, 0.28f, 1.0f}}});
        mDivBound.PushConstant(commandBuffer, mCentre);
        mDivBound.Record(commandBuffer);
        div.Barrier(commandBuffer, vk::AccessFlagBits::eShaderWrite, vk::AccessFlagBits::eShaderRead);
        commandBuffer.debugMarkerEndEXT();
    });
}

void RigidBody::BindVelocityConstrain(Fluid::Velocity& velocity)
{
    mConstrainBound = mConstrain.Bind({velocity, velocity.Output(), mPhi, mVelocity, mMVBuffer});
    mConstrainCmd.Record([&](vk::CommandBuffer commandBuffer)
    {
        commandBuffer.debugMarkerBeginEXT({"Rigidbody constrain", {{0.29f, 0.36f, 0.21f, 1.0f}}});
        mConstrainBound.PushConstant(commandBuffer, mCentre);
        mConstrainBound.Record(commandBuffer);
        velocity.CopyBack(commandBuffer);
        commandBuffer.debugMarkerEndEXT();
    });
}

void RigidBody::BindForce(Renderer::GenericBuffer& diagonal,
                          Renderer::GenericBuffer& pressure)
{
    mForceBound = mForceWork.Bind({diagonal, mPhi, pressure, mForce, mMVBuffer});
    mLocalSumBound = mSum.Bind(mForce, mLocalForce);
    mForceCmd.Record([&](vk::CommandBuffer commandBuffer)
    {
        commandBuffer.debugMarkerBeginEXT({"Rigidbody force", {{0.70f, 0.59f, 0.63f, 1.0f}}});
        mForce.Clear(commandBuffer);
        mForceBound.PushConstant(commandBuffer, mCentre);
        mForceBound.Record(commandBuffer);
        mForce.Barrier(commandBuffer, vk::AccessFlagBits::eShaderWrite, vk::AccessFlagBits::eShaderRead);
        mLocalSumBound.Record(commandBuffer);
        commandBuffer.debugMarkerEndEXT();
    });
}

void RigidBody::BindPressure(Renderer::GenericBuffer& d,
                             Renderer::GenericBuffer& s,
                             Renderer::GenericBuffer& z)
{
    mPressureForceBound = mForceWork.Bind({d, mPhi, s, mForce, mMVBuffer});
    mPressureBound = mPressureWork.Bind({d, mPhi, mReducedForce, z, mMVBuffer});
    mSumBound = mSum.Bind(mForce, mReducedForce);
    mPressureCmd.Record([&](vk::CommandBuffer commandBuffer)
    {
        commandBuffer.debugMarkerBeginEXT({"Rigidbody pressure", {{0.70f, 0.59f, 0.63f, 1.0f}}});
        mForce.Clear(commandBuffer);
        mPressureForceBound.PushConstant(commandBuffer, mCentre);
        mPressureForceBound.Record(commandBuffer);
        mForce.Barrier(commandBuffer, vk::AccessFlagBits::eShaderWrite, vk::AccessFlagBits::eShaderRead);
        mSumBound.Record(commandBuffer);
        mPressureBound.PushConstant(commandBuffer, mCentre, mDelta, mMass, mInertia);
        mPressureBound.Record(commandBuffer);
        z.Barrier(commandBuffer, vk::AccessFlagBits::eShaderWrite, vk::AccessFlagBits::eShaderRead);
        commandBuffer.debugMarkerEndEXT();
    });
}

void RigidBody::Div()
{
    mDivCmd.Submit();
}

void RigidBody::Force()
{
    mForceCmd.Submit();
}

void RigidBody::Pressure()
{
    mPressureCmd.Submit();
}

void RigidBody::VelocityConstrain()
{
    mConstrainCmd.Submit();
}

vk::Flags<RigidBody::Type> RigidBody::GetType()
{
    return mType;
}

Renderer::RenderTexture& RigidBody::Phi()
{
    return mPhi;
}

}}
<|endoftext|>