<commit_before>#ifdef HAVE_CMAKE_CONFIG
#include "cmake_config.h"
#elif defined(HAVE_CONFIG_H)
#include "config.h"
#endif

#define HAVE_DUNE_DETAILED_DISCRETIZATIONS 1

#include <iostream>
#include <sstream>
#include <vector>

#include <boost/filesystem.hpp>

#include <dune/common/exceptions.hh>
#include <dune/common/static_assert.hh>
#include <dune/common/timer.hh>
#include <dune/common/dynvector.hh>

#include <dune/grid/io/file/vtk/vtkwriter.hh>

#include <dune/grid/part/leaf.hh>

#include <dune/fem/misc/mpimanager.hh>
#include <dune/fem/space/common/functionspace.hh>

#include <dune/stuff/common/parameter/tree.hh>
#include <dune/stuff/common/logging.hh>
#include <dune/stuff/grid/provider.hh>
#include <dune/stuff/grid/boundaryinfo.hh>
#include <dune/stuff/function/expression.hh>
#include <dune/stuff/la/solver.hh>
#include <dune/stuff/discretefunction/projection/dirichlet.hh>

#include <dune/detailed/discretizations/space/continuouslagrange/fem.hh>
#include <dune/detailed/discretizations/la/containerfactory/eigen.hh>
#include <dune/detailed/discretizations/evaluation/elliptic.hh>
#include <dune/detailed/discretizations/evaluation/product.hh>
#include <dune/detailed/discretizations/localoperator/codim0.hh>
#include <dune/detailed/discretizations/localfunctional/codim0.hh>
#include <dune/detailed/discretizations/assembler/local/codim0.hh>
#include <dune/detailed/discretizations/space/constraints.hh>
#include <dune/detailed/discretizations/assembler/system.hh>
#include <dune/detailed/discretizations/discretefunction/default.hh>

const std::string id = "elliptic.continuousgalerkin";

#ifndef POLORDER
const int polOrder = 1;
#else
const int polOrder = POLORDER;
#endif
dune_static_assert((polOrder > 0), "ERROR: polOrder hast to be positive!");

using namespace Dune::Detailed::Discretizations;

/**
  \brief      Creates a parameter file if it does not exist.

              Nothing is done if the file already exists. If not, a parameter file will be created with all neccessary
              keys and values.
  \param[in]  filename
              (Relative) path to the file.
  **/
void ensureParamFile(const std::string& filename)
{
  // only write param file if there is none
  if (!boost::filesystem::exists(filename)) {
    std::ofstream file;
    file.open(filename);
    file << "[" << id << "]" << std::endl;
    file << "filename = " << id << std::endl;
    file << "grid = "
         << "gridprovider.cube" << std::endl;
    file << "boundaryinfo = "
         << "boundaryinfo.alldirichlet" << std::endl;
    file << "[gridprovider.cube]" << std::endl;
    file << "lowerLeft = [0.0; 0.0; 0.0]" << std::endl;
    file << "upperRight = [1.0; 1.0; 1.0]" << std::endl;
    file << "numElements = [12; 12; 12]" << std::endl;
    file << "[boundaryinfo.idbased]" << std::endl;
    file << "dirichlet = [1; 2; 3]" << std::endl;
    file << "neumann = [4]" << std::endl;
    file << "[diffusion]" << std::endl;
    file << "order = 0" << std::endl;
    file << "variable = x" << std::endl;
    file << "expression = [1.0; 1.0; 1.0]" << std::endl;
    file << "[force]" << std::endl;
    file << "order = 0" << std::endl;
    file << "variable = x" << std::endl;
    file << "expression = [1.0; 1.0; 1.0]" << std::endl;
    file << "[dirichlet]" << std::endl;
    file << "order = 0" << std::endl;
    file << "variable = x" << std::endl;
    file << "expression = [0.1*x[0]; 0.0; 0.0]" << std::endl;
    file << "[neumann]" << std::endl;
    file << "order = 0" << std::endl;
    file << "variable = x" << std::endl;
    file << "expression = [1.0; 0.0; 0.0]" << std::endl;
    file << "[solver]" << std::endl;
    file << "type = bicgstab.ilut" << std::endl;
    file << "maxIter = 5000" << std::endl;
    file << "precision = 1e-12" << std::endl;
    file.close();
  } // only write param file if there is none
} // void ensureParamFile()

int main(int argc, char** argv)
{
  try {
    // mpi
    Dune::Fem::MPIManager::initialize(argc, argv);

    // parameter
    const std::string paramFilename = id + ".description";
    ensureParamFile(paramFilename);
    Dune::Stuff::Common::ExtendedParameterTree description(argc, argv, paramFilename);
    description.assertSub(id);

    // logger
    Dune::Stuff::Common::Logger().create(Dune::Stuff::Common::LOG_INFO | Dune::Stuff::Common::LOG_CONSOLE);
    Dune::Stuff::Common::LogStream& info = Dune::Stuff::Common::Logger().info();

    // timer
    Dune::Timer timer;

    info << "setting up grid:" << std::endl;
    typedef Dune::Stuff::GridProviderInterface<> GridProviderType;
    const GridProviderType* gridProvider =
        Dune::Stuff::GridProviders<>::create(description.get(id + ".grid", "gridprovider.cube"), description);
    typedef GridProviderType::GridType GridType;
    const std::shared_ptr<const GridType> grid = gridProvider->grid();
    typedef Dune::grid::Part::Leaf::Const<GridType> GridPartType;
    typedef typename GridPartType::GridViewType GridViewType;
    const GridPartType gridPart(*grid);
    typedef typename Dune::Stuff::GridboundaryInterface<typename GridPartType::GridViewType> BoundaryInfoType;
    const std::shared_ptr<const BoundaryInfoType> boundaryInfo(
        Dune::Stuff::Gridboundaries<typename GridPartType::GridViewType>::create(
            description.get(id + ".boundaryinfo", "boundaryinfo.alldirichlet"), description));
    info << "  took " << timer.elapsed() << " sec, has " << grid->size(0) << " entities" << std::endl;
    info << "visualizing grid... " << std::flush;
    timer.reset();
    gridProvider->visualize(description.get(id + ".boundaryinfo", "boundaryinfo.alldirichlet"),
                            description,
                            description.get(id + ".filename", id) + ".grid");
    info << " done (took " << timer.elapsed() << " sek)" << std::endl;

    const unsigned int DUNE_UNUSED(dimDomain) = GridProviderType::dim;
    const unsigned int DUNE_UNUSED(dimRange) = 1;
    typedef typename GridType::ctype DomainFieldType;
    typedef double RangeFieldType;

    typedef Dune::Stuff::FunctionExpression<DomainFieldType, dimDomain, RangeFieldType, dimRange>
        ExpressionFunctionType;
    const std::shared_ptr<const ExpressionFunctionType> diffusion(
        ExpressionFunctionType::create(description.sub("diffusion")));
    const std::shared_ptr<const ExpressionFunctionType> force(ExpressionFunctionType::create(description.sub("force")));
    const std::shared_ptr<const ExpressionFunctionType> dirichlet(
        ExpressionFunctionType::create(description.sub("dirichlet")));
    const std::shared_ptr<const ExpressionFunctionType> neumann(
        ExpressionFunctionType::create(description.sub("neumann")));

    // info << "initializing discrete function spaces... " << std::flush;
    // timer.reset();
    typedef ContinuousLagrangeSpace::FemWrapper<GridPartType, polOrder, RangeFieldType, dimRange> SpaceType;
    const SpaceType space(gridPart);

    // left hand side
    // * elliptic diffusion operator
    typedef LocalOperatorCodim0Integral<Evaluation::Elliptic, ExpressionFunctionType> EllipticOperatorType;
    const EllipticOperatorType diffusionOperator(*diffusion);
    // * right hand side
    //   * L2 force functional
    typedef LocalFunctionalCodim0Integral<Evaluation::Product, ExpressionFunctionType> L2FunctionalType;
    const L2FunctionalType forceFunctional(*force);
    //   * L2 neumann functional
    const L2FunctionalType neumannFunctional(*neumann);

    info << "initializing matrix (of size " << space.mapper().size() << "x" << space.mapper().size()
         << ") and vectors... " << std::flush;
    // timer.reset();
    typedef ContainerFactoryEigen<RangeFieldType> ContainerFactory;
    typedef ContainerFactory::RowMajorSparseMatrixType MatrixType;
    typedef ContainerFactory::DenseVectorType VectorType;
    std::shared_ptr<MatrixType> systemMatrix(ContainerFactory::createRowMajorSparseMatrix(space, space));
    std::shared_ptr<VectorType> forceVector(ContainerFactory::createDenseVector(space));
    std::shared_ptr<VectorType> dirichletVector(ContainerFactory::createDenseVector(space));
    std::shared_ptr<VectorType> neumannVector(ContainerFactory::createDenseVector(space));
    std::shared_ptr<VectorType> rhsVector(ContainerFactory::createDenseVector(space));
    std::shared_ptr<VectorType> solutionVector(ContainerFactory::createDenseVector(space));
    info << "done (took " << timer.elapsed() << " sec)" << std::endl;

    info << "assembing system... " << std::flush;
    timer.reset();
    // * dirichlet boundary values
    typedef DiscreteFunctionDefault<SpaceType, VectorType> DiscreteFunctionType;
    DiscreteFunctionType dirichletProjection(space, dirichletVector, "dirichlet");
    Dune::Stuff::DiscreteFunction::project(*boundaryInfo, *dirichlet, dirichletProjection);

    // * local matrix assembler
    typedef LocalAssemblerCodim0Matrix<EllipticOperatorType> LocalEllipticOperatorMatrixAssemblerType;
    const LocalEllipticOperatorMatrixAssemblerType diffusionMatrixAssembler(diffusionOperator);
    // * local vector assemblers
    typedef LocalAssemblerCodim0Vector<L2FunctionalType> LocalL2FunctionalVectorAssemblerType;
    //   * force vector
    const LocalL2FunctionalVectorAssemblerType forceVectorAssembler(forceFunctional);
    //   * neumann vector
    const LocalL2FunctionalVectorAssemblerType neumannVectorAssembler(neumannFunctional);
    // * system assembler
    typedef SystemAssembler<SpaceType, SpaceType> SystemAssemblerType;
    SystemAssemblerType systemAssembler(space);
    systemAssembler.addLocalMatrixAssembler(diffusionMatrixAssembler, *systemMatrix);
    systemAssembler.addLocalVectorAssembler(forceVectorAssembler, *forceVector);
    systemAssembler.addLocalVectorAssembler(neumannVectorAssembler, *neumannVector);
    systemAssembler.assemble();
    info << "done (took " << timer.elapsed() << " sec)" << std::endl;

    info << "applying constraints... " << std::flush;
    timer.reset();
    Constraints::Dirichlet<GridViewType, RangeFieldType> dirichletConstraints(
        *boundaryInfo, space.mapper().maxNumDofs(), space.mapper().maxNumDofs());
    rhsVector->backend() =
        forceVector->backend() + neumannVector->backend() - systemMatrix->backend() * dirichletVector->backend();
    systemAssembler.applyConstraints(dirichletConstraints, *systemMatrix, *rhsVector);
    info << "done (took " << timer.elapsed() << " sec)" << std::endl;

    info << "solving linear system (of size " << systemMatrix->rows() << "x" << systemMatrix->cols() << ")"
         << std::endl;
    const std::string solverType     = description.get("solver.type", "bicgstab");
    const unsigned int solverMaxIter = description.get("solver.maxIter", 5000);
    const double solverPrecision     = description.get("solver.precision", 1e-12);
    info << "  using '" << solverType << "'... " << std::flush;
    timer.reset();
    typedef typename Dune::Stuff::LA::Solver::Interface<MatrixType, VectorType> SolverType;
    std::shared_ptr<SolverType> solver(Dune::Stuff::LA::Solver::create<MatrixType, VectorType>(solverType));
    const unsigned int failure =
        solver->apply(*systemMatrix, *rhsVector, *solutionVector, solverMaxIter, solverPrecision);
    if (failure)
      DUNE_THROW(Dune::MathError, "\nERROR: linear solver '" << solverType << "' reported a problem!");
    if (solutionVector->size() != space.mapper().size())
      DUNE_THROW(Dune::MathError,
                 "\nERROR: linear solver '" << solverType << "' produced a solution of wrong size (is "
                                            << solutionVector->size()
                                            << ", should be "
                                            << space.mapper().size()
                                            << ")!");
    solutionVector->backend() += dirichletVector->backend();
    info << "done (took " << timer.elapsed() << " sec)" << std::endl;

    const std::string solutionFilename = description.get(id + ".filename", id) + ".solution";
    const std::string solutionName     = id + ".solution";
    info << "writing solution to '" << solutionFilename;
    if (dimDomain == 1)
      info << ".vtp";
    else
      info << ".vtu";
    info << "'... " << std::flush;
    timer.reset();
    typedef DiscreteFunctionDefaultConst<SpaceType, VectorType> ConstDiscreteFunctionType;
    const std::shared_ptr<const ConstDiscreteFunctionType> solution(
        new ConstDiscreteFunctionType(space, solutionVector, solutionName));
    typedef Dune::VTKWriter<GridViewType> VTKWriterType;
    VTKWriterType vtkWriter(gridPart.gridView());
    vtkWriter.addVertexData(solution);
    vtkWriter.write(solutionFilename);
    info << "done (took " << timer.elapsed() << " sec)" << std::endl;

    // done
    return 0;
  } catch (Dune::Exception& e) {
    std::cerr << "Dune reported error: " << e.what() << std::endl;
  } catch (std::exception& e) {
    std::cerr << e.what() << std::endl;
  } catch (...) {
    std::cerr << "Unknown exception thrown!" << std::endl;
  } // try
} // main
<commit_msg>[examples.elliptic.continuousgalerkin] update<commit_after>#ifdef HAVE_CMAKE_CONFIG
#include "cmake_config.h"
#elif defined(HAVE_CONFIG_H)
#include "config.h"
#endif

#define HAVE_DUNE_DETAILED_DISCRETIZATIONS 1

#include <iostream>
#include <sstream>
#include <vector>

#include <boost/filesystem.hpp>

#include <dune/common/exceptions.hh>
#include <dune/common/static_assert.hh>
#include <dune/common/timer.hh>
#include <dune/common/dynvector.hh>

#include <dune/grid/io/file/vtk/vtkwriter.hh>

#include <dune/grid/part/leaf.hh>

#include <dune/fem/misc/mpimanager.hh>
#include <dune/fem/space/common/functionspace.hh>

#include <dune/stuff/common/parameter/tree.hh>
#include <dune/stuff/common/logging.hh>
#include <dune/stuff/grid/provider.hh>
#include <dune/stuff/grid/boundaryinfo.hh>
#include <dune/stuff/function/expression.hh>
#include <dune/stuff/la/solver.hh>
#include <dune/stuff/discretefunction/projection/dirichlet.hh>

#include <dune/detailed/discretizations/space/continuouslagrange/fem.hh>
#include <dune/detailed/discretizations/la/containerfactory/eigen.hh>
#include <dune/detailed/discretizations/evaluation/elliptic.hh>
#include <dune/detailed/discretizations/evaluation/product.hh>
#include <dune/detailed/discretizations/localoperator/codim0.hh>
#include <dune/detailed/discretizations/localfunctional/codim0.hh>
#include <dune/detailed/discretizations/assembler/local/codim0.hh>
#include <dune/detailed/discretizations/space/constraints.hh>
#include <dune/detailed/discretizations/assembler/system.hh>
#include <dune/detailed/discretizations/discretefunction/default.hh>

const std::string id = "elliptic.continuousgalerkin";

#ifndef POLORDER
const int polOrder = 1;
#else
const int polOrder = POLORDER;
#endif
dune_static_assert((polOrder > 0), "ERROR: polOrder hast to be positive!");

using namespace Dune::Detailed::Discretizations;

/**
  \brief      Creates a parameter file if it does not exist.

              Nothing is done if the file already exists. If not, a parameter file will be created with all neccessary
              keys and values.
  \param[in]  filename
              (Relative) path to the file.
  **/
void ensureParamFile(const std::string& filename)
{
  // only write param file if there is none
  if (!boost::filesystem::exists(filename)) {
    std::ofstream file;
    file.open(filename);
    file << "[" << id << "]" << std::endl;
    file << "filename = " << id << std::endl;
    file << "grid = "
         << "gridprovider.cube" << std::endl;
    file << "boundaryinfo = "
         << "boundaryinfo.alldirichlet" << std::endl;
    file << "[gridprovider.cube]" << std::endl;
    file << "lowerLeft = [0.0; 0.0; 0.0]" << std::endl;
    file << "upperRight = [1.0; 1.0; 1.0]" << std::endl;
    file << "numElements = [12; 12; 12]" << std::endl;
    file << "[boundaryinfo.idbased]" << std::endl;
    file << "dirichlet = [1; 2; 3]" << std::endl;
    file << "neumann = [4]" << std::endl;
    file << "[diffusion]" << std::endl;
    file << "order = 0" << std::endl;
    file << "variable = x" << std::endl;
    file << "expression = [1.0; 1.0; 1.0]" << std::endl;
    file << "[force]" << std::endl;
    file << "order = 0" << std::endl;
    file << "variable = x" << std::endl;
    file << "expression = [1.0; 1.0; 1.0]" << std::endl;
    file << "[dirichlet]" << std::endl;
    file << "order = 0" << std::endl;
    file << "variable = x" << std::endl;
    file << "expression = [0.1*x[0]; 0.0; 0.0]" << std::endl;
    file << "[neumann]" << std::endl;
    file << "order = 0" << std::endl;
    file << "variable = x" << std::endl;
    file << "expression = [1.0; 0.0; 0.0]" << std::endl;
    file << "[solver]" << std::endl;
    file << "type = bicgstab.ilut" << std::endl;
    file << "maxIter = 5000" << std::endl;
    file << "precision = 1e-12" << std::endl;
    file.close();
  } // only write param file if there is none
} // void ensureParamFile()

int main(int argc, char** argv)
{
  try {
    // mpi
    Dune::Fem::MPIManager::initialize(argc, argv);

    // parameter
    const std::string paramFilename = id + ".description";
    ensureParamFile(paramFilename);
    Dune::Stuff::Common::ExtendedParameterTree description(argc, argv, paramFilename);
    description.assertSub(id);

    // logger
    Dune::Stuff::Common::Logger().create(Dune::Stuff::Common::LOG_INFO | Dune::Stuff::Common::LOG_CONSOLE);
    Dune::Stuff::Common::LogStream& info = Dune::Stuff::Common::Logger().info();

    // timer
    Dune::Timer timer;

    info << "setting up grid:" << std::endl;
    typedef Dune::Stuff::GridProviderInterface<> GridProviderType;
    const GridProviderType* gridProvider =
        Dune::Stuff::GridProviders<>::create(description.get(id + ".grid", "gridprovider.cube"), description);
    typedef GridProviderType::GridType GridType;
    const std::shared_ptr<const GridType> grid = gridProvider->grid();
    typedef Dune::grid::Part::Leaf::Const<GridType> GridPartType;
    typedef typename GridPartType::GridViewType GridViewType;
    const GridPartType gridPart(*grid);
    typedef typename Dune::Stuff::GridboundaryInterface<typename GridPartType::GridViewType> BoundaryInfoType;
    const std::shared_ptr<const BoundaryInfoType> boundaryInfo(
        Dune::Stuff::Gridboundaries<typename GridPartType::GridViewType>::create(
            description.get(id + ".boundaryinfo", "boundaryinfo.alldirichlet"), description));
    info << "  took " << timer.elapsed() << " sec, has " << grid->size(0) << " entities" << std::endl;
    info << "visualizing grid... " << std::flush;
    timer.reset();
    gridProvider->visualize(description.get(id + ".boundaryinfo", "boundaryinfo.alldirichlet"),
                            description,
                            description.get(id + ".filename", id) + ".grid");
    info << " done (took " << timer.elapsed() << " sek)" << std::endl;

    const unsigned int DUNE_UNUSED(dimDomain) = GridProviderType::dim;
    const unsigned int DUNE_UNUSED(dimRange) = 1;
    typedef typename GridType::ctype DomainFieldType;
    typedef double RangeFieldType;

    typedef Dune::Stuff::FunctionExpression<DomainFieldType, dimDomain, RangeFieldType, dimRange>
        ExpressionFunctionType;
    const std::shared_ptr<const ExpressionFunctionType> diffusion(
        ExpressionFunctionType::create(description.sub("diffusion")));
    const std::shared_ptr<const ExpressionFunctionType> force(ExpressionFunctionType::create(description.sub("force")));
    const std::shared_ptr<const ExpressionFunctionType> dirichlet(
        ExpressionFunctionType::create(description.sub("dirichlet")));
    const std::shared_ptr<const ExpressionFunctionType> neumann(
        ExpressionFunctionType::create(description.sub("neumann")));

    // info << "initializing discrete function spaces... " << std::flush;
    // timer.reset();
    typedef ContinuousLagrangeSpace::FemWrapper<GridPartType, polOrder, RangeFieldType, dimRange> SpaceType;
    const SpaceType space(gridPart);

    // left hand side
    // * elliptic diffusion operator
    typedef LocalOperator::Codim0Integral<Evaluation::Elliptic, ExpressionFunctionType> EllipticOperatorType;
    const EllipticOperatorType diffusionOperator(*diffusion);
    // * right hand side
    //   * L2 force functional
    typedef LocalFunctional::Codim0Integral<Evaluation::Product, ExpressionFunctionType> L2FunctionalType;
    const L2FunctionalType forceFunctional(*force);
    //   * L2 neumann functional
    const L2FunctionalType neumannFunctional(*neumann);

    info << "initializing matrix (of size " << space.mapper().size() << "x" << space.mapper().size()
         << ") and vectors... " << std::flush;
    // timer.reset();
    typedef ContainerFactoryEigen<RangeFieldType> ContainerFactory;
    typedef ContainerFactory::RowMajorSparseMatrixType MatrixType;
    typedef ContainerFactory::DenseVectorType VectorType;
    std::shared_ptr<MatrixType> systemMatrix(ContainerFactory::createRowMajorSparseMatrix(space, space));
    std::shared_ptr<VectorType> forceVector(ContainerFactory::createDenseVector(space));
    std::shared_ptr<VectorType> dirichletVector(ContainerFactory::createDenseVector(space));
    std::shared_ptr<VectorType> neumannVector(ContainerFactory::createDenseVector(space));
    std::shared_ptr<VectorType> rhsVector(ContainerFactory::createDenseVector(space));
    std::shared_ptr<VectorType> solutionVector(ContainerFactory::createDenseVector(space));
    info << "done (took " << timer.elapsed() << " sec)" << std::endl;

    info << "assembing system... " << std::flush;
    timer.reset();
    // * dirichlet boundary values
    typedef DiscreteFunctionDefault<SpaceType, VectorType> DiscreteFunctionType;
    DiscreteFunctionType dirichletProjection(space, dirichletVector, "dirichlet");
    Dune::Stuff::DiscreteFunction::project(*boundaryInfo, *dirichlet, dirichletProjection);

    // * local matrix assembler
    typedef LocalAssembler::Codim0Matrix<EllipticOperatorType> LocalEllipticOperatorMatrixAssemblerType;
    const LocalEllipticOperatorMatrixAssemblerType diffusionMatrixAssembler(diffusionOperator);
    // * local vector assemblers
    typedef LocalAssembler::Codim0Vector<L2FunctionalType> LocalL2FunctionalVectorAssemblerType;
    //   * force vector
    const LocalL2FunctionalVectorAssemblerType forceVectorAssembler(forceFunctional);
    //   * neumann vector
    const LocalL2FunctionalVectorAssemblerType neumannVectorAssembler(neumannFunctional);
    // * system assembler
    typedef SystemAssembler<SpaceType, SpaceType> SystemAssemblerType;
    SystemAssemblerType systemAssembler(space);
    systemAssembler.addLocalMatrixAssembler(diffusionMatrixAssembler, *systemMatrix);
    systemAssembler.addLocalVectorAssembler(forceVectorAssembler, *forceVector);
    systemAssembler.addLocalVectorAssembler(neumannVectorAssembler, *neumannVector);
    systemAssembler.assemble();
    info << "done (took " << timer.elapsed() << " sec)" << std::endl;

    info << "applying constraints... " << std::flush;
    timer.reset();
    Constraints::Dirichlet<GridViewType, RangeFieldType> dirichletConstraints(
        *boundaryInfo, space.mapper().maxNumDofs(), space.mapper().maxNumDofs());
    rhsVector->backend() =
        forceVector->backend() + neumannVector->backend() - systemMatrix->backend() * dirichletVector->backend();
    systemAssembler.applyConstraints(dirichletConstraints, *systemMatrix, *rhsVector);
    info << "done (took " << timer.elapsed() << " sec)" << std::endl;

    info << "solving linear system (of size " << systemMatrix->rows() << "x" << systemMatrix->cols() << ")"
         << std::endl;
    const std::string solverType     = description.get("solver.type", "bicgstab");
    const unsigned int solverMaxIter = description.get("solver.maxIter", 5000);
    const double solverPrecision     = description.get("solver.precision", 1e-12);
    info << "  using '" << solverType << "'... " << std::flush;
    timer.reset();
    typedef typename Dune::Stuff::LA::Solver::Interface<MatrixType, VectorType> SolverType;
    std::shared_ptr<SolverType> solver(Dune::Stuff::LA::Solver::create<MatrixType, VectorType>(solverType));
    const unsigned int failure =
        solver->apply(*systemMatrix, *rhsVector, *solutionVector, solverMaxIter, solverPrecision);
    if (failure)
      DUNE_THROW(Dune::MathError, "\nERROR: linear solver '" << solverType << "' reported a problem!");
    if (solutionVector->size() != space.mapper().size())
      DUNE_THROW(Dune::MathError,
                 "\nERROR: linear solver '" << solverType << "' produced a solution of wrong size (is "
                                            << solutionVector->size()
                                            << ", should be "
                                            << space.mapper().size()
                                            << ")!");
    solutionVector->backend() += dirichletVector->backend();
    info << "done (took " << timer.elapsed() << " sec)" << std::endl;

    const std::string solutionFilename = description.get(id + ".filename", id) + ".solution";
    const std::string solutionName     = id + ".solution";
    info << "writing solution to '" << solutionFilename;
    if (dimDomain == 1)
      info << ".vtp";
    else
      info << ".vtu";
    info << "'... " << std::flush;
    timer.reset();
    typedef DiscreteFunctionDefaultConst<SpaceType, VectorType> ConstDiscreteFunctionType;
    const std::shared_ptr<const ConstDiscreteFunctionType> solution(
        new ConstDiscreteFunctionType(space, solutionVector, solutionName));
    typedef Dune::VTKWriter<GridViewType> VTKWriterType;
    VTKWriterType vtkWriter(gridPart.gridView());
    vtkWriter.addVertexData(solution);
    vtkWriter.write(solutionFilename);
    info << "done (took " << timer.elapsed() << " sec)" << std::endl;

    // done
    return 0;
  } catch (Dune::Exception& e) {
    std::cerr << "Dune reported error: " << e.what() << std::endl;
  } catch (std::exception& e) {
    std::cerr << e.what() << std::endl;
  } catch (...) {
    std::cerr << "Unknown exception thrown!" << std::endl;
  } // try
} // main
<|endoftext|>


<commit_before>#include <chord.h>
#include <dhash.h>
#include <dhash_common.h>
#include <dhashcli.h>

#include <libadb.h>

#include <dhblock_chash.h>
#include <dhblock_chash_srv.h>

#include "pmaint.h"

#include <configurator.h>
#include <locationtable.h>
#include <ida.h>

#include <modlogger.h>
#define warning modlogger ("dhblock_chash", modlogger::WARNING)
#define info  modlogger ("dhblock_chash", modlogger::INFO)
#define trace modlogger ("dhblock_chash", modlogger::TRACE)

#ifdef DMALLOC
#include <dmalloc.h>
#endif

struct rjchash : public repair_job {
  rjchash (blockID key, ptr<location> w, ptr<dhblock_chash_srv> bsrv);

  const ptr<dhblock_chash_srv> bsrv;

  void execute ();
  // 1. Check cache db and send frag if present.
  // 2. Else retrieve the block
  // 3. Cache it and send frag.

  // Async callbacks
  void cache_check_cb (adb_status stat, chordID key, str d);
  void retrieve_cb (dhash_stat err, ptr<dhash_block> b, route r);
  void send_frag (str block);
  void local_store_cb (dhash_stat stat);
  void send_frag_cb (dhash_stat err, bool present);
};

dhblock_chash_srv::dhblock_chash_srv (ptr<vnode> node,
				      ptr<dhashcli> cli,
				      str msock,
				      str dbsock,
				      str dbname,
				      cbv donecb) :
  dhblock_srv (node, cli, DHASH_CONTENTHASH, msock,
      dbsock, dbname, false, donecb),
  cache_db (NULL),
  pmaint_obj (NULL)
{
  pmaint_obj = New pmaint (cli, node, mkref (this));
  cache_db = New refcounted<adb> (dbsock, "ccache");
  maint_initspace (dhblock_chash::num_efrags (),
		   dhblock_chash::num_dfrags ());

  (*donecb)();

}

dhblock_chash_srv::~dhblock_chash_srv ()
{
  stop ();
  if (pmaint_obj) {
    delete pmaint_obj;
    pmaint_obj = NULL;
  }
}

void
dhblock_chash_srv::start (bool randomize)
{
  dhblock_srv::start (randomize);
  // XXX disable pmaint until DHASHPROC_OFFER is fixed.
  if (0 && pmaint_obj)
    pmaint_obj->start ();
}

void
dhblock_chash_srv::stop ()
{
  dhblock_srv::stop ();
  if (pmaint_obj)
    pmaint_obj->stop ();
}

void
dhblock_chash_srv::store (chordID key, str d, cb_dhstat cb)
{
  char *action;

  if (1) {  // without maintaining our own merkle tree, we can't know
    action = "N"; // New
    db_store (key, d, cb);
  } else {
    action = "R";
    cb (DHASH_OK);
  }
  // Force a BSM update just in case it was confused.
  db->update (key, node->my_location (), true);

  bigint h = compute_hash (d.cstr (), d.len ());
  info << "db write: " << node->my_ID () << " " << action
       << " " << key << " " << d.len ()
       << " " << h
       << "\n";
}

void
dhblock_chash_srv::generate_repair_jobs ()
{
  u_int32_t frags = dhblock_chash::num_efrags ();
  vec<ptr<location> > preds = node->preds ();
  chordID rngmin;
  if (preds.size () >= frags)
    rngmin = preds[frags - 1]->id ();
  else
    rngmin = incID (node->my_location ()->id ());
  maint_getrepairs (frags, REPAIR_QUEUE_MAX - repair_qlength (),
      rngmin,
      wrap (this, &dhblock_chash_srv::maintqueue));
#if 0
  // Use of db's view of repairs is deprecated.
  u_int32_t frags = dhblock_chash::num_dfrags ();
  db->getblockrange (node->my_pred ()->id (), node->my_location ()->id (),
		     frags, REPAIR_QUEUE_MAX - repair_qlength (),
		     wrap (this, &dhblock_chash_srv::localqueue, frags));
#endif /* 0 */
}

void
dhblock_chash_srv::maintqueue (const vec<maint_repair_t> &repairs)
{
  for (size_t i = 0; i < repairs.size (); i++) {
    ptr<location> w = maintloc2location (
	repairs[i].machine_order_ipv4_addr,
	repairs[i].machine_order_port_vnnum);
    blockID key (repairs[i].id, DHASH_CONTENTHASH);
    ptr<repair_job> job = New refcounted<rjchash> (key, w,
	mkref (this));
    repair_add (job);
  }
}

void
dhblock_chash_srv::localqueue (u_int32_t frags,
    clnt_stat err, adb_status stat, vec<block_info> blocks)
{
  if (err) {
    return;
  } else if (stat == ADB_ERR) {
    warning << "dhblock_chash_srv::localqueue: adb error, failing.\n";
    return;
  }

  trace << "chash-localqueue (" << node->my_ID() << "): repairing "
	<< blocks.size() << " blocks with " << frags
	<< " frags\n";
  if( blocks.size() > 0 ) {
    trace << "first block=" << blocks[0].k << "\n";
  }

  //don't assume we are holding the block
  // i.e. -> put ourselves on this of nodes to check for the block
  vec<ptr<location> > nmsuccs = node->succs ();
  vec<ptr<location> > succs;
  succs.push_back (node->my_location ());
  for (size_t j = 0; j < nmsuccs.size (); j++)
    succs.push_back (nmsuccs[j]);

  bhash<chordID, hashID> holders;
  for (size_t i = 0; i < blocks.size (); i++) {

    // Should always be true, but fails occasionally for me. maybe the db
    // was non transactionally correcting? -- strib, 2/8/06
    //assert (blocks[i].on.size () == frags);

    holders.clear ();
    for (size_t j = 0; j < blocks[i].on.size (); j++)
      holders.insert (blocks[i].on[j].x);

    blockID key (blocks[i].k, DHASH_CONTENTHASH);
    ptr<location> w = NULL;
    u_int32_t reps = 0;
    for (size_t j = 0; j < succs.size (); j++) {
      w = succs[j];
      if (!holders[w->id ()] && reps < dhblock_chash::num_efrags () - frags) {
	ptr<repair_job> job = New refcounted<rjchash> (key, w, mkref (this));
	repair_add (job);
	reps++;
	break;
      }
    }
  }

  if (repair_qlength () < REPAIR_QUEUE_MAX) {
    // Expect blocks to be sorted (since DB_DUPSORT is set)
    chordID nstart;
    if (stat == ADB_COMPLETE) {
      frags++;
      nstart = node->my_pred ()->id ();
    } else {
      nstart = incID( blocks.back ().k );
    }
    if (frags < dhblock_chash::num_efrags ())
      db->getblockrange (nstart, node->my_location ()->id (),
	  frags, REPAIR_QUEUE_MAX - repair_qlength (),
	  wrap (this, &dhblock_chash_srv::localqueue, frags));
  }
}

// XXX Ugh
// This code is called in response to an RPC.  Unfortunately, now
// we need to go out to disk to figure out the best way to respond.
void
dhblock_chash_srv::offer (user_args *sbp, dhash_offer_arg *arg)
{
  dhash_offer_res res (DHASH_OK);
  res.resok->accepted.setsize (arg->keys.size ());
  res.resok->dest.setsize (arg->keys.size ());

  //XXX copied code
  vec<ptr<location> > nmsuccs = node->succs ();
  //don't assume we are holding the block
  // i.e. -> put ourselves on this of nodes to check for the block
  vec<ptr<location> > succs;
  succs.push_back (node->my_location ());
  for (unsigned int j = 0; j < nmsuccs.size (); j++)
    succs.push_back(nmsuccs[j]);
  //XXX end copied
#if 0
  for (u_int i = 0; i < arg->keys.size (); i++) {
    chordID key = arg->keys[i];
    u_int count = bsm->pcount (key, succs);
    chordID pred = node->my_pred ()->id ();
    bool mine = between (pred, node->my_ID (), key);

    // belongs to me and isn't replicated well
    if (mine && count < dhblock_chash::num_efrags ()) {
      res.resok->accepted[i] = DHASH_SENDTO;
      ptr<location> l = bsm->best_missing (key, node->succs ());
      trace << "server: sending " << key << ": count=" << count
	    << " to=" << l->id () << "\n";
      l->fill_node (res.resok->dest[i]);
      bsm->unmissing (l, key);
    } else {
      trace << "server: holding " << key << ": count=" << count << "\n";
      res.resok->accepted[i] = DHASH_HOLD;
    }
  }
#endif /* 0 */

  sbp->reply (&res);
}

void
dhblock_chash_srv::stats (vec<dstat> &s)
{
  warn << "chash stats no longer supported\n";
  return;
}

//
// Repair Logic Implementation
//
rjchash::rjchash (blockID key, ptr<location> w,
		  ptr<dhblock_chash_srv> bsrv) :
    repair_job (key, w),
    bsrv (bsrv)
{
}

void
rjchash::execute ()
{
  bsrv->cache_db->fetch (key.ID,
      wrap (mkref (this), &rjchash::cache_check_cb));
}

void
rjchash::cache_check_cb (adb_status stat, chordID k, str d)
{
  if (stat == ADB_OK) {
    assert (key.ID == k);
    send_frag (d);
  } else {
    bsrv->cli->retrieve (key,
	wrap (mkref (this), &rjchash::retrieve_cb));
  }
}

static void cache_store_cb (adb_status stat);
void
rjchash::retrieve_cb (dhash_stat err, ptr<dhash_block> b, route r)
{
  if (err) {
    trace << "retrieve missing block " << key << " failed: " << err << "\n";
    // We'll probably try again later.
    // XXX maybe make sure we don't try too "often"?
  } else {
    assert (b);
    bsrv->cache_db->store (key.ID, b->data, wrap (cache_store_cb));
    send_frag (b->data);
  }
}

static void
cache_store_cb (adb_status stat)
{
  if (stat != ADB_OK)
    warn << "store error caching block: " << stat << "\n";
}

void
rjchash::send_frag (str block)
{
  u_long m = Ida::optimal_dfrag (block.len (), dhblock::dhash_mtu ());
  if (m > dhblock_chash::num_dfrags ())
    m = dhblock_chash::num_dfrags ();
  str frag = Ida::gen_frag (m, block);

  //if the block will be sent to us, just store it instead of sending
  // an RPC to ourselves. This will happen a lot, so the optmization
  // is probably worth it.
  if (where == bsrv->node->my_location ()) {
    bsrv->store (key.ID, frag,
	wrap (mkref (this), &rjchash::local_store_cb));
  } else {
    bsrv->cli->sendblock (where, key, frag,
	wrap (mkref (this), &rjchash::send_frag_cb));
  }
}

void
rjchash::local_store_cb (dhash_stat stat)
{
  if (stat != DHASH_OK) {
    warning << "dhblock_chash_srv database store error: "
	    << stat << "\n";
  } else {
    info << "repair: " << bsrv->node->my_ID ()
	 << " sent " << key << " to " << where->id () <<  " (me).\n";
  }
}

void
rjchash::send_frag_cb (dhash_stat err, bool present)
{
  strbuf x;
  x << "repair: " << bsrv->node->my_ID ();
  if (!err) {
    bsrv->db->update (key.ID, where, true);
    x << " sent ";
  } else {
    x << " error sending ";
  }
  x << key << " to " << where->id ();
  if (err)
    x << " (" << err << ")";
  info << x << ".\n";
}

<commit_msg>Backed out changeset afba9eff35bf7ee7ec8cb078ad431c23f4dc969b<commit_after>#include <chord.h>
#include <dhash.h>
#include <dhash_common.h>
#include <dhashcli.h>

#include <libadb.h>

#include <dhblock_chash.h>
#include <dhblock_chash_srv.h>

#include "pmaint.h"

#include <configurator.h>
#include <locationtable.h>
#include <ida.h>

#include <modlogger.h>
#define warning modlogger ("dhblock_chash", modlogger::WARNING)
#define info  modlogger ("dhblock_chash", modlogger::INFO)
#define trace modlogger ("dhblock_chash", modlogger::TRACE)

#ifdef DMALLOC
#include <dmalloc.h>
#endif

struct rjchash : public repair_job {
  rjchash (blockID key, ptr<location> w, ptr<dhblock_chash_srv> bsrv);

  const ptr<dhblock_chash_srv> bsrv;

  void execute ();
  // 1. Check cache db and send frag if present.
  // 2. Else retrieve the block
  // 3. Cache it and send frag.

  // Async callbacks
  void cache_check_cb (adb_status stat, chordID key, str d);
  void retrieve_cb (dhash_stat err, ptr<dhash_block> b, route r);
  void send_frag (str block);
  void local_store_cb (dhash_stat stat);
  void send_frag_cb (dhash_stat err, bool present);
};

dhblock_chash_srv::dhblock_chash_srv (ptr<vnode> node,
				      ptr<dhashcli> cli,
				      str msock,
				      str dbsock,
				      str dbname,
				      cbv donecb) :
  dhblock_srv (node, cli, DHASH_CONTENTHASH, msock,
      dbsock, dbname, false, donecb),
  cache_db (NULL),
  pmaint_obj (NULL)
{
  pmaint_obj = New pmaint (cli, node, mkref (this));
  cache_db = New refcounted<adb> (dbsock, "ccache");
  maint_initspace (dhblock_chash::num_efrags (),
		   dhblock_chash::num_dfrags ());

  (*donecb)();

}

dhblock_chash_srv::~dhblock_chash_srv ()
{
  stop ();
  if (pmaint_obj) {
    delete pmaint_obj;
    pmaint_obj = NULL;
  }
}

void
dhblock_chash_srv::start (bool randomize)
{
  dhblock_srv::start (randomize);
  // XXX disable pmaint until DHASHPROC_OFFER is fixed.
  if (0 && pmaint_obj)
    pmaint_obj->start ();
}

void
dhblock_chash_srv::stop ()
{
  dhblock_srv::stop ();
  if (pmaint_obj)
    pmaint_obj->stop ();
}

void
dhblock_chash_srv::store (chordID key, str d, cb_dhstat cb)
{
  char *action;

  if (1) {  // without maintaining our own merkle tree, we can't know
    action = "N"; // New
    db_store (key, d, cb);
  } else {
    action = "R";
    cb (DHASH_OK);
  }
  // Force a BSM update just in case it was confused.
  db->update (key, node->my_location (), true);

  bigint h = compute_hash (d.cstr (), d.len ());
  info << "db write: " << node->my_ID () << " " << action
       << " " << key << " " << d.len ()
       << " " << h
       << "\n";
}

void
dhblock_chash_srv::generate_repair_jobs ()
{
  u_int32_t frags = dhblock_chash::num_efrags ();
  maint_getrepairs (frags, REPAIR_QUEUE_MAX - repair_qlength (),
      node->my_pred ()->id (),
      wrap (this, &dhblock_chash_srv::maintqueue));
#if 0
  // Use of db's view of repairs is deprecated.
  u_int32_t frags = dhblock_chash::num_dfrags ();
  db->getblockrange (node->my_pred ()->id (), node->my_location ()->id (),
		     frags, REPAIR_QUEUE_MAX - repair_qlength (),
		     wrap (this, &dhblock_chash_srv::localqueue, frags));
#endif /* 0 */
}

void
dhblock_chash_srv::maintqueue (const vec<maint_repair_t> &repairs)
{
  for (size_t i = 0; i < repairs.size (); i++) {
    ptr<location> w = maintloc2location (
	repairs[i].machine_order_ipv4_addr,
	repairs[i].machine_order_port_vnnum);
    blockID key (repairs[i].id, DHASH_CONTENTHASH);
    ptr<repair_job> job = New refcounted<rjchash> (key, w,
	mkref (this));
    repair_add (job);
  }
}

void
dhblock_chash_srv::localqueue (u_int32_t frags,
    clnt_stat err, adb_status stat, vec<block_info> blocks)
{
  if (err) {
    return;
  } else if (stat == ADB_ERR) {
    warning << "dhblock_chash_srv::localqueue: adb error, failing.\n";
    return;
  }

  trace << "chash-localqueue (" << node->my_ID() << "): repairing "
	<< blocks.size() << " blocks with " << frags
	<< " frags\n";
  if( blocks.size() > 0 ) {
    trace << "first block=" << blocks[0].k << "\n";
  }

  //don't assume we are holding the block
  // i.e. -> put ourselves on this of nodes to check for the block
  vec<ptr<location> > nmsuccs = node->succs ();
  vec<ptr<location> > succs;
  succs.push_back (node->my_location ());
  for (size_t j = 0; j < nmsuccs.size (); j++)
    succs.push_back (nmsuccs[j]);

  bhash<chordID, hashID> holders;
  for (size_t i = 0; i < blocks.size (); i++) {

    // Should always be true, but fails occasionally for me. maybe the db
    // was non transactionally correcting? -- strib, 2/8/06
    //assert (blocks[i].on.size () == frags);

    holders.clear ();
    for (size_t j = 0; j < blocks[i].on.size (); j++)
      holders.insert (blocks[i].on[j].x);

    blockID key (blocks[i].k, DHASH_CONTENTHASH);
    ptr<location> w = NULL;
    u_int32_t reps = 0;
    for (size_t j = 0; j < succs.size (); j++) {
      w = succs[j];
      if (!holders[w->id ()] && reps < dhblock_chash::num_efrags () - frags) {
	ptr<repair_job> job = New refcounted<rjchash> (key, w, mkref (this));
	repair_add (job);
	reps++;
	break;
      }
    }
  }

  if (repair_qlength () < REPAIR_QUEUE_MAX) {
    // Expect blocks to be sorted (since DB_DUPSORT is set)
    chordID nstart;
    if (stat == ADB_COMPLETE) {
      frags++;
      nstart = node->my_pred ()->id ();
    } else {
      nstart = incID( blocks.back ().k );
    }
    if (frags < dhblock_chash::num_efrags ())
      db->getblockrange (nstart, node->my_location ()->id (),
	  frags, REPAIR_QUEUE_MAX - repair_qlength (),
	  wrap (this, &dhblock_chash_srv::localqueue, frags));
  }
}

// XXX Ugh
// This code is called in response to an RPC.  Unfortunately, now
// we need to go out to disk to figure out the best way to respond.
void
dhblock_chash_srv::offer (user_args *sbp, dhash_offer_arg *arg)
{
  dhash_offer_res res (DHASH_OK);
  res.resok->accepted.setsize (arg->keys.size ());
  res.resok->dest.setsize (arg->keys.size ());

  //XXX copied code
  vec<ptr<location> > nmsuccs = node->succs ();
  //don't assume we are holding the block
  // i.e. -> put ourselves on this of nodes to check for the block
  vec<ptr<location> > succs;
  succs.push_back (node->my_location ());
  for (unsigned int j = 0; j < nmsuccs.size (); j++)
    succs.push_back(nmsuccs[j]);
  //XXX end copied
#if 0
  for (u_int i = 0; i < arg->keys.size (); i++) {
    chordID key = arg->keys[i];
    u_int count = bsm->pcount (key, succs);
    chordID pred = node->my_pred ()->id ();
    bool mine = between (pred, node->my_ID (), key);

    // belongs to me and isn't replicated well
    if (mine && count < dhblock_chash::num_efrags ()) {
      res.resok->accepted[i] = DHASH_SENDTO;
      ptr<location> l = bsm->best_missing (key, node->succs ());
      trace << "server: sending " << key << ": count=" << count
	    << " to=" << l->id () << "\n";
      l->fill_node (res.resok->dest[i]);
      bsm->unmissing (l, key);
    } else {
      trace << "server: holding " << key << ": count=" << count << "\n";
      res.resok->accepted[i] = DHASH_HOLD;
    }
  }
#endif /* 0 */

  sbp->reply (&res);
}

void
dhblock_chash_srv::stats (vec<dstat> &s)
{
  warn << "chash stats no longer supported\n";
  return;
}

//
// Repair Logic Implementation
//
rjchash::rjchash (blockID key, ptr<location> w,
		  ptr<dhblock_chash_srv> bsrv) :
    repair_job (key, w),
    bsrv (bsrv)
{
}

void
rjchash::execute ()
{
  bsrv->cache_db->fetch (key.ID,
      wrap (mkref (this), &rjchash::cache_check_cb));
}

void
rjchash::cache_check_cb (adb_status stat, chordID k, str d)
{
  if (stat == ADB_OK) {
    assert (key.ID == k);
    send_frag (d);
  } else {
    bsrv->cli->retrieve (key,
	wrap (mkref (this), &rjchash::retrieve_cb));
  }
}

static void cache_store_cb (adb_status stat);
void
rjchash::retrieve_cb (dhash_stat err, ptr<dhash_block> b, route r)
{
  if (err) {
    trace << "retrieve missing block " << key << " failed: " << err << "\n";
    // We'll probably try again later.
    // XXX maybe make sure we don't try too "often"?
  } else {
    assert (b);
    bsrv->cache_db->store (key.ID, b->data, wrap (cache_store_cb));
    send_frag (b->data);
  }
}

static void
cache_store_cb (adb_status stat)
{
  if (stat != ADB_OK)
    warn << "store error caching block: " << stat << "\n";
}

void
rjchash::send_frag (str block)
{
  u_long m = Ida::optimal_dfrag (block.len (), dhblock::dhash_mtu ());
  if (m > dhblock_chash::num_dfrags ())
    m = dhblock_chash::num_dfrags ();
  str frag = Ida::gen_frag (m, block);

  //if the block will be sent to us, just store it instead of sending
  // an RPC to ourselves. This will happen a lot, so the optmization
  // is probably worth it.
  if (where == bsrv->node->my_location ()) {
    bsrv->store (key.ID, frag,
	wrap (mkref (this), &rjchash::local_store_cb));
  } else {
    bsrv->cli->sendblock (where, key, frag,
	wrap (mkref (this), &rjchash::send_frag_cb));
  }
}

void
rjchash::local_store_cb (dhash_stat stat)
{
  if (stat != DHASH_OK) {
    warning << "dhblock_chash_srv database store error: "
	    << stat << "\n";
  } else {
    info << "repair: " << bsrv->node->my_ID ()
	 << " sent " << key << " to " << where->id () <<  " (me).\n";
  }
}

void
rjchash::send_frag_cb (dhash_stat err, bool present)
{
  strbuf x;
  x << "repair: " << bsrv->node->my_ID ();
  if (!err) {
    bsrv->db->update (key.ID, where, true);
    x << " sent ";
  } else {
    x << " error sending ";
  }
  x << key << " to " << where->id ();
  if (err)
    x << " (" << err << ")";
  info << x << ".\n";
}

<|endoftext|>


<commit_before>/*
  Copyright (c) 2011-2012 - Tőkés Attila
  Copyright (C) 2015 Daniel Nicoletti <dantti12@gmail.com>

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

  This library 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
  Lesser General Public License for more details.

  See the LICENSE file for more details.
*/

#include "mimemessage_p.h"

#include <QtCore/QDebug>
#include "quotedprintable.h"
#include <typeinfo>

#include <QDateTime>
#include <QLocale>
#include <QLoggingCategory>

Q_LOGGING_CATEGORY(SIMPLEMAIL_MIMEMSG, "simplemail.mimemessage")

using namespace SimpleMail;

MimeMessage::MimeMessage(bool createAutoMimeContent) :
    d_ptr(new MimeMessagePrivate)
{
    Q_D(MimeMessage);
    if (createAutoMimeContent) {
        d->content = new MimeMultiPart();
    }

    d->autoMimeContentCreated = createAutoMimeContent;
}

MimeMessage::~MimeMessage()
{
    delete d_ptr;
}

MimePart& MimeMessage::getContent()
{
    Q_D(MimeMessage);
    return *d->content;
}

void MimeMessage::setContent(MimePart *content)
{
    Q_D(MimeMessage);
    if (d->autoMimeContentCreated) {
      d->autoMimeContentCreated = false;
      delete d->content;
    }
    d->content = content;
}

bool MimeMessage::write(QIODevice *device)
{
    Q_D(const MimeMessage);

    // Headers
    QByteArray data;

    data = MimeMessagePrivate::encode(QByteArrayLiteral("From: "), QList<EmailAddress>() << d->sender, d->encoding);
    if (device->write(data) != data.size()) {
        return false;
    }

    data = MimeMessagePrivate::encode(QByteArrayLiteral("To: "), d->recipientsTo, d->encoding);
    if (device->write(data) != data.size()) {
        return false;
    }

    data = MimeMessagePrivate::encode(QByteArrayLiteral("Cc: "), d->recipientsCc, d->encoding);
    if (device->write(data) != data.size()) {
        return false;
    }

    const auto dt = QDateTime::currentDateTime();
    data = QByteArrayLiteral("Date: ") + QLocale::c().toString(dt, QStringLiteral("ddd, d MMM yyyy HH:mm:ss ")).toLatin1();
    int utcOffset = dt.offsetFromUtc();
    if (utcOffset == 0) {
        data.append(QByteArrayLiteral("+0000"));
    } else {
        const bool negative = (utcOffset < 0);
        if (negative) {
            data.append('-');
            utcOffset *= -1;
        } else {
            data.append('+');
        }
        const auto offsetTime = QTime::fromMSecsSinceStartOfDay(utcOffset * 1000);
        data.append(offsetTime.toString(QStringLiteral("HHmm")).toLatin1());
    }

    data = QByteArrayLiteral("Subject: ") + MimeMessagePrivate::encodeData(d->encoding, d->subject, true);
    if (device->write(data) != data.size()) {
        return false;
    }

    data = QByteArrayLiteral("\r\nMIME-Version: 1.0\r\n");
    if (device->write(data) != data.size()) {
        return false;
    }

    if (!d->content->write(device)) {
        return false;
    }

    return true;
}

void MimeMessage::setSender(const EmailAddress &sender)
{
    Q_D(MimeMessage);
    d->sender = sender;
}

void MimeMessage::setToRecipients(const QList<EmailAddress> &toList)
{
    Q_D(MimeMessage);
    d->recipientsTo = toList;
}

QList<EmailAddress> MimeMessage::toRecipients() const
{
    Q_D(const MimeMessage);
    return d->recipientsTo;
}

void MimeMessage::addTo(const EmailAddress &rcpt)
{
    Q_D(MimeMessage);
    d->recipientsTo.append(rcpt);
}

void MimeMessage::setCcRecipients(const QList<EmailAddress> &ccList)
{
    Q_D(MimeMessage);
    d->recipientsCc = ccList;
}

void MimeMessage::addCc(const EmailAddress &rcpt)
{
    Q_D(MimeMessage);
    d->recipientsCc.append(rcpt);
}

QList<EmailAddress> MimeMessage::ccRecipients() const
{
    Q_D(const MimeMessage);
    return d->recipientsCc;
}

void MimeMessage::setBccRecipients(const QList<EmailAddress> &bccList)
{
    Q_D(MimeMessage);
    d->recipientsBcc = bccList;
}

QList<EmailAddress> MimeMessage::bccRecipients() const
{
    Q_D(const MimeMessage);
    return d->recipientsBcc;
}

void MimeMessage::addBcc(const EmailAddress &rcpt)
{
    Q_D(MimeMessage);
    d->recipientsBcc.append(rcpt);
}

void MimeMessage::setSubject(const QString & subject)
{
    Q_D(MimeMessage);
    d->subject = subject;
}

void MimeMessage::addPart(MimePart *part)
{
    Q_D(MimeMessage);
    if (typeid(*d->content) == typeid(MimeMultiPart)) {
        ((MimeMultiPart*) d->content)->addPart(part);
    }
}

void MimeMessage::setHeaderEncoding(MimePart::Encoding hEnc)
{
    Q_D(MimeMessage);
    d->encoding = hEnc;
}

EmailAddress MimeMessage::sender() const
{
    Q_D(const MimeMessage);
    return d->sender;
}

QString MimeMessage::subject() const
{
    Q_D(const MimeMessage);
    return d->subject;
}

QList<MimePart*> MimeMessage::parts() const
{
    Q_D(const MimeMessage);

    QList<MimePart*> ret;
    if (typeid(*d->content) == typeid(MimeMultiPart)) {
        ret = static_cast<MimeMultiPart*>(d->content)->parts();
    } else {
        ret.append(d->content);
    }

    return ret;
}

MimeMessagePrivate::~MimeMessagePrivate()
{
    delete content;
}

QByteArray MimeMessagePrivate::encode(const QByteArray &addressKind, const QList<EmailAddress> &emails, MimePart::Encoding codec)
{
    if (emails.isEmpty()) {
        return QByteArray();
    }

    QByteArray mime = addressKind;
    bool first = true;
    for (const EmailAddress &email : emails) {
        if (!first) {
            mime.append(',');
        } else {
            first = false;
        }

        const QString name = email.name();
        if (!name.isEmpty()) {
            mime.append(MimeMessagePrivate::encodeData(codec, name, true));
            mime.append(" <" + email.address().toLatin1() + '>');
        } else {
            mime.append('<' + email.address().toLatin1() + '>');
        }
    }
    mime.append(QByteArrayLiteral("\r\n"));

    return mime;
}

QByteArray MimeMessagePrivate::encodeData(MimePart::Encoding codec, const QString &data, bool autoencoding)
{
    const QString simpleData = data.simplified();
    const QByteArray simple = simpleData.toUtf8();
    if (autoencoding) {
        if (simpleData.toLatin1() == simple) {
            return simple;
        }

        int printable = 0;
        int encoded = 0;
        const QByteArray result = QuotedPrintable::encode(simple, true, &printable, &encoded);
        int sum = printable + encoded;
        qCDebug(SIMPLEMAIL_MIMEMSG) << data << result << printable << encoded << sum << ((double) printable/sum) << (encoded/sum);
        if (sum != 0 && ((double) printable/sum) >= 0.8) {
            return " =?utf-8?Q?" + result + "?=";
        } else {
            return " =?utf-8?B?" + data.toUtf8().toBase64() + "?=";
        }
    } else {
        switch (codec) {
        case MimePart::Base64:
            return " =?utf-8?B?" + simple.toBase64() + "?=";
        case MimePart::QuotedPrintable:
            return " =?utf-8?Q?" + QuotedPrintable::encode(simple, true) + "?=";
        default:
            return ' ' + data.toLatin1();
        }
    }
}
<commit_msg>Write Date header filed to output.<commit_after>/*
  Copyright (c) 2011-2012 - Tőkés Attila
  Copyright (C) 2015 Daniel Nicoletti <dantti12@gmail.com>

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

  This library 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
  Lesser General Public License for more details.

  See the LICENSE file for more details.
*/

#include "mimemessage_p.h"

#include <QtCore/QDebug>
#include "quotedprintable.h"
#include <typeinfo>

#include <QDateTime>
#include <QLocale>
#include <QLoggingCategory>

Q_LOGGING_CATEGORY(SIMPLEMAIL_MIMEMSG, "simplemail.mimemessage")

using namespace SimpleMail;

MimeMessage::MimeMessage(bool createAutoMimeContent) :
    d_ptr(new MimeMessagePrivate)
{
    Q_D(MimeMessage);
    if (createAutoMimeContent) {
        d->content = new MimeMultiPart();
    }

    d->autoMimeContentCreated = createAutoMimeContent;
}

MimeMessage::~MimeMessage()
{
    delete d_ptr;
}

MimePart& MimeMessage::getContent()
{
    Q_D(MimeMessage);
    return *d->content;
}

void MimeMessage::setContent(MimePart *content)
{
    Q_D(MimeMessage);
    if (d->autoMimeContentCreated) {
      d->autoMimeContentCreated = false;
      delete d->content;
    }
    d->content = content;
}

bool MimeMessage::write(QIODevice *device)
{
    Q_D(const MimeMessage);

    // Headers
    QByteArray data;

    data = MimeMessagePrivate::encode(QByteArrayLiteral("From: "), QList<EmailAddress>() << d->sender, d->encoding);
    if (device->write(data) != data.size()) {
        return false;
    }

    data = MimeMessagePrivate::encode(QByteArrayLiteral("To: "), d->recipientsTo, d->encoding);
    if (device->write(data) != data.size()) {
        return false;
    }

    data = MimeMessagePrivate::encode(QByteArrayLiteral("Cc: "), d->recipientsCc, d->encoding);
    if (device->write(data) != data.size()) {
        return false;
    }

    const auto dt = QDateTime::currentDateTime();
    data = QByteArrayLiteral("Date: ") + QLocale::c().toString(dt, QStringLiteral("ddd, d MMM yyyy HH:mm:ss ")).toLatin1();
    int utcOffset = dt.offsetFromUtc();
    if (utcOffset == 0) {
        data.append(QByteArrayLiteral("+0000"));
    } else {
        const bool negative = (utcOffset < 0);
        if (negative) {
            data.append('-');
            utcOffset *= -1;
        } else {
            data.append('+');
        }
        const auto offsetTime = QTime::fromMSecsSinceStartOfDay(utcOffset * 1000);
        data.append(offsetTime.toString(QStringLiteral("HHmm")).toLatin1());
    }
    if (device->write(data) != data.size()) {
        return false;
    }

    data = QByteArrayLiteral("Subject: ") + MimeMessagePrivate::encodeData(d->encoding, d->subject, true);
    if (device->write(data) != data.size()) {
        return false;
    }

    data = QByteArrayLiteral("\r\nMIME-Version: 1.0\r\n");
    if (device->write(data) != data.size()) {
        return false;
    }

    if (!d->content->write(device)) {
        return false;
    }

    return true;
}

void MimeMessage::setSender(const EmailAddress &sender)
{
    Q_D(MimeMessage);
    d->sender = sender;
}

void MimeMessage::setToRecipients(const QList<EmailAddress> &toList)
{
    Q_D(MimeMessage);
    d->recipientsTo = toList;
}

QList<EmailAddress> MimeMessage::toRecipients() const
{
    Q_D(const MimeMessage);
    return d->recipientsTo;
}

void MimeMessage::addTo(const EmailAddress &rcpt)
{
    Q_D(MimeMessage);
    d->recipientsTo.append(rcpt);
}

void MimeMessage::setCcRecipients(const QList<EmailAddress> &ccList)
{
    Q_D(MimeMessage);
    d->recipientsCc = ccList;
}

void MimeMessage::addCc(const EmailAddress &rcpt)
{
    Q_D(MimeMessage);
    d->recipientsCc.append(rcpt);
}

QList<EmailAddress> MimeMessage::ccRecipients() const
{
    Q_D(const MimeMessage);
    return d->recipientsCc;
}

void MimeMessage::setBccRecipients(const QList<EmailAddress> &bccList)
{
    Q_D(MimeMessage);
    d->recipientsBcc = bccList;
}

QList<EmailAddress> MimeMessage::bccRecipients() const
{
    Q_D(const MimeMessage);
    return d->recipientsBcc;
}

void MimeMessage::addBcc(const EmailAddress &rcpt)
{
    Q_D(MimeMessage);
    d->recipientsBcc.append(rcpt);
}

void MimeMessage::setSubject(const QString & subject)
{
    Q_D(MimeMessage);
    d->subject = subject;
}

void MimeMessage::addPart(MimePart *part)
{
    Q_D(MimeMessage);
    if (typeid(*d->content) == typeid(MimeMultiPart)) {
        ((MimeMultiPart*) d->content)->addPart(part);
    }
}

void MimeMessage::setHeaderEncoding(MimePart::Encoding hEnc)
{
    Q_D(MimeMessage);
    d->encoding = hEnc;
}

EmailAddress MimeMessage::sender() const
{
    Q_D(const MimeMessage);
    return d->sender;
}

QString MimeMessage::subject() const
{
    Q_D(const MimeMessage);
    return d->subject;
}

QList<MimePart*> MimeMessage::parts() const
{
    Q_D(const MimeMessage);

    QList<MimePart*> ret;
    if (typeid(*d->content) == typeid(MimeMultiPart)) {
        ret = static_cast<MimeMultiPart*>(d->content)->parts();
    } else {
        ret.append(d->content);
    }

    return ret;
}

MimeMessagePrivate::~MimeMessagePrivate()
{
    delete content;
}

QByteArray MimeMessagePrivate::encode(const QByteArray &addressKind, const QList<EmailAddress> &emails, MimePart::Encoding codec)
{
    if (emails.isEmpty()) {
        return QByteArray();
    }

    QByteArray mime = addressKind;
    bool first = true;
    for (const EmailAddress &email : emails) {
        if (!first) {
            mime.append(',');
        } else {
            first = false;
        }

        const QString name = email.name();
        if (!name.isEmpty()) {
            mime.append(MimeMessagePrivate::encodeData(codec, name, true));
            mime.append(" <" + email.address().toLatin1() + '>');
        } else {
            mime.append('<' + email.address().toLatin1() + '>');
        }
    }
    mime.append(QByteArrayLiteral("\r\n"));

    return mime;
}

QByteArray MimeMessagePrivate::encodeData(MimePart::Encoding codec, const QString &data, bool autoencoding)
{
    const QString simpleData = data.simplified();
    const QByteArray simple = simpleData.toUtf8();
    if (autoencoding) {
        if (simpleData.toLatin1() == simple) {
            return simple;
        }

        int printable = 0;
        int encoded = 0;
        const QByteArray result = QuotedPrintable::encode(simple, true, &printable, &encoded);
        int sum = printable + encoded;
        qCDebug(SIMPLEMAIL_MIMEMSG) << data << result << printable << encoded << sum << ((double) printable/sum) << (encoded/sum);
        if (sum != 0 && ((double) printable/sum) >= 0.8) {
            return " =?utf-8?Q?" + result + "?=";
        } else {
            return " =?utf-8?B?" + data.toUtf8().toBase64() + "?=";
        }
    } else {
        switch (codec) {
        case MimePart::Base64:
            return " =?utf-8?B?" + simple.toBase64() + "?=";
        case MimePart::QuotedPrintable:
            return " =?utf-8?Q?" + QuotedPrintable::encode(simple, true) + "?=";
        default:
            return ' ' + data.toLatin1();
        }
    }
}
<|endoftext|>


<commit_before>#ifndef GLM_FORCE_RADIANS
#define GLM_FORCE_RADIANS
#define DEGREES_TO_RADIANS(x) (x * PI / 180.0f)
#endif

#include "ascii_grid_loader.hpp"
#include "code/ylikuutio/triangulation/quad_triangulation.hpp"
#include "code/ylikuutio/string/ylikuutio_string.hpp"
#include "code/ylikuutio/common/globals.hpp"
#include "code/ylikuutio/common/global_variables.hpp"

// Include GLM
#ifndef __GLM_GLM_HPP_INCLUDED
#define __GLM_GLM_HPP_INCLUDED
#include <glm/glm.hpp> // glm
#endif

// Include standard headers
#include <cmath>    // NAN, std::isnan, std::pow
#include <cstdio>   // std::FILE, std::fclose, std::fopen, std::fread, std::getchar, std::printf etc.
#include <iostream> // std::cout, std::cin, std::cerr
#include <stdint.h> // uint32_t etc.
#include <string>   // std::string, std::stoi
#include <vector>   // std::vector

namespace loaders
{
    bool load_ascii_grid(
            std::string ascii_grid_file_name,
            std::vector<glm::vec3>& out_vertices,
            std::vector<glm::vec2>& out_UVs,
            std::vector<glm::vec3>& out_normals,
            std::string triangulation_type)
    {
        // Beginning of `L4133D.asc`.
        //
        // ncols        3000
        // nrows        3000
        // xllcorner    386000.000000000000
        // yllcorner    6672000.000000000000
        // cellsize     2.000000000000
        // NODATA_value  -9999.000
        // 34.315 34.467 34.441 34.260 33.972 33.564 33.229 33.130 33.102 33.024 32.902 32.669 32.305 32.013 31.937 31.893 31.831 31.832

        std::cout << "Loading ascii grid file " << ascii_grid_file_name << " ...\n";

        // Open the file
        const char* char_ascii_grid_file_name = ascii_grid_file_name.c_str();
        std::FILE* file = std::fopen(char_ascii_grid_file_name, "rb");
        if (!file)
        {
            std::cerr << ascii_grid_file_name << " could not be opened.\n";
            return false;
        }

        // Find out file size.
        if (std::fseek(file, 0, SEEK_END) != 0)
        {
            std::cerr << "moving file pointer of file " << ascii_grid_file_name << " failed!\n";
            std::fclose(file);
            return false;
        }

        uint64_t file_size = std::ftell(file);

        // Move file pointer to the beginning of file.
        if (fseek(file, 0, SEEK_SET) != 0)
        {
            std::cerr << "moving file pointer of file " << ascii_grid_file_name << " failed!\n";
            std::fclose(file);
            return false;
        }

        // Reserve enough memory.
        char* point_data = new char[file_size];
        char* point_data_pointer = point_data;

        // Read the point data from the file into the buffer.
        std::fread(point_data, 1, file_size, file);

        // Everything is in memory now, the file can be closed
        std::fclose(file);

        // All possible block identifier strings.
        std::vector<std::string> number_strings_vector = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };

        while (!string::check_and_report_if_some_string_matches(point_data, point_data_pointer, number_strings_vector))
        {
            point_data_pointer++;
        }
        int32_t image_width = string::extract_int32_t_value_from_string(point_data_pointer, (char*) " \n", (const char*) "ncols");

        while (!string::check_and_report_if_some_string_matches(point_data, point_data_pointer, number_strings_vector))
        {
            point_data_pointer++;
        }
        int32_t image_height = string::extract_int32_t_value_from_string(point_data_pointer, (char*) " \n", (const char*) "nrows");

        while (!string::check_and_report_if_some_string_matches(point_data, point_data_pointer, number_strings_vector))
        {
            point_data_pointer++;
        }
        float xllcorner = string::extract_float_value_from_string(point_data_pointer, (char*) " \n", (const char*) "xllcorner");

        while (!string::check_and_report_if_some_string_matches(point_data, point_data_pointer, number_strings_vector))
        {
            point_data_pointer++;
        }
        float yllcorner = string::extract_float_value_from_string(point_data_pointer, (char*) " \n", (const char*) "yllcorner");

        while (!string::check_and_report_if_some_string_matches(point_data, point_data_pointer, number_strings_vector))
        {
            point_data_pointer++;
        }
        float cellsize = string::extract_float_value_from_string(point_data_pointer, (char*) " \n", (const char*) "cellsize");

        while (!string::check_and_report_if_some_string_matches(point_data, point_data_pointer, number_strings_vector))
        {
            point_data_pointer++;
        }
        float nodata_value = string::extract_float_value_from_string(point_data_pointer, (char*) " \n", (const char*) "nodata_value");

        uint32_t image_width_in_use = 3000; // should be 3000.
        uint32_t image_height_in_use = 1000;

        float* vertex_data;
        vertex_data = new float[image_width_in_use * image_height_in_use];

        float* vertex_pointer;
        vertex_pointer = vertex_data;

        // start processing image_data.

        for (uint32_t z = 0; z < image_height_in_use; z++)
        {
            for (uint32_t x = 0; x < image_width_in_use; x++)
            {
                while (!string::check_and_report_if_some_string_matches(point_data, point_data_pointer, number_strings_vector))
                {
                    point_data_pointer++;
                }
                *vertex_pointer++ = string::extract_float_value_from_string(point_data_pointer, (char*) " \n", (const char*) nullptr);
            }
        }

        delete point_data;

        std::cout << "Triangulating ascii grid data.\n";

        TriangulateQuadsStruct triangulate_quads_struct;
        // triangulate_quads_struct.image_width = image_width;
        triangulate_quads_struct.image_width = image_width_in_use;
        triangulate_quads_struct.image_height = image_height_in_use;
        triangulate_quads_struct.triangulation_type = triangulation_type;
        triangulate_quads_struct.sphere_radius = NAN;
        triangulate_quads_struct.spherical_world_struct = SphericalWorldStruct(); // not used, but is needed in the function call.

        bool result = geometry::triangulate_quads(vertex_data, triangulate_quads_struct, out_vertices, out_UVs, out_normals);
        delete vertex_data;
        return true;
    }
}
<commit_msg>Use 2000 first lines of ASCII grid elevation model.<commit_after>#ifndef GLM_FORCE_RADIANS
#define GLM_FORCE_RADIANS
#define DEGREES_TO_RADIANS(x) (x * PI / 180.0f)
#endif

#include "ascii_grid_loader.hpp"
#include "code/ylikuutio/triangulation/quad_triangulation.hpp"
#include "code/ylikuutio/string/ylikuutio_string.hpp"
#include "code/ylikuutio/common/globals.hpp"
#include "code/ylikuutio/common/global_variables.hpp"

// Include GLM
#ifndef __GLM_GLM_HPP_INCLUDED
#define __GLM_GLM_HPP_INCLUDED
#include <glm/glm.hpp> // glm
#endif

// Include standard headers
#include <cmath>    // NAN, std::isnan, std::pow
#include <cstdio>   // std::FILE, std::fclose, std::fopen, std::fread, std::getchar, std::printf etc.
#include <iostream> // std::cout, std::cin, std::cerr
#include <stdint.h> // uint32_t etc.
#include <string>   // std::string, std::stoi
#include <vector>   // std::vector

namespace loaders
{
    bool load_ascii_grid(
            std::string ascii_grid_file_name,
            std::vector<glm::vec3>& out_vertices,
            std::vector<glm::vec2>& out_UVs,
            std::vector<glm::vec3>& out_normals,
            std::string triangulation_type)
    {
        // Beginning of `L4133D.asc`.
        //
        // ncols        3000
        // nrows        3000
        // xllcorner    386000.000000000000
        // yllcorner    6672000.000000000000
        // cellsize     2.000000000000
        // NODATA_value  -9999.000
        // 34.315 34.467 34.441 34.260 33.972 33.564 33.229 33.130 33.102 33.024 32.902 32.669 32.305 32.013 31.937 31.893 31.831 31.832

        std::cout << "Loading ascii grid file " << ascii_grid_file_name << " ...\n";

        // Open the file
        const char* char_ascii_grid_file_name = ascii_grid_file_name.c_str();
        std::FILE* file = std::fopen(char_ascii_grid_file_name, "rb");
        if (!file)
        {
            std::cerr << ascii_grid_file_name << " could not be opened.\n";
            return false;
        }

        // Find out file size.
        if (std::fseek(file, 0, SEEK_END) != 0)
        {
            std::cerr << "moving file pointer of file " << ascii_grid_file_name << " failed!\n";
            std::fclose(file);
            return false;
        }

        uint64_t file_size = std::ftell(file);

        // Move file pointer to the beginning of file.
        if (fseek(file, 0, SEEK_SET) != 0)
        {
            std::cerr << "moving file pointer of file " << ascii_grid_file_name << " failed!\n";
            std::fclose(file);
            return false;
        }

        // Reserve enough memory.
        char* point_data = new char[file_size];
        char* point_data_pointer = point_data;

        // Read the point data from the file into the buffer.
        std::fread(point_data, 1, file_size, file);

        // Everything is in memory now, the file can be closed
        std::fclose(file);

        // All possible block identifier strings.
        std::vector<std::string> number_strings_vector = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };

        while (!string::check_and_report_if_some_string_matches(point_data, point_data_pointer, number_strings_vector))
        {
            point_data_pointer++;
        }
        int32_t image_width = string::extract_int32_t_value_from_string(point_data_pointer, (char*) " \n", (const char*) "ncols");

        while (!string::check_and_report_if_some_string_matches(point_data, point_data_pointer, number_strings_vector))
        {
            point_data_pointer++;
        }
        int32_t image_height = string::extract_int32_t_value_from_string(point_data_pointer, (char*) " \n", (const char*) "nrows");

        while (!string::check_and_report_if_some_string_matches(point_data, point_data_pointer, number_strings_vector))
        {
            point_data_pointer++;
        }
        float xllcorner = string::extract_float_value_from_string(point_data_pointer, (char*) " \n", (const char*) "xllcorner");

        while (!string::check_and_report_if_some_string_matches(point_data, point_data_pointer, number_strings_vector))
        {
            point_data_pointer++;
        }
        float yllcorner = string::extract_float_value_from_string(point_data_pointer, (char*) " \n", (const char*) "yllcorner");

        while (!string::check_and_report_if_some_string_matches(point_data, point_data_pointer, number_strings_vector))
        {
            point_data_pointer++;
        }
        float cellsize = string::extract_float_value_from_string(point_data_pointer, (char*) " \n", (const char*) "cellsize");

        while (!string::check_and_report_if_some_string_matches(point_data, point_data_pointer, number_strings_vector))
        {
            point_data_pointer++;
        }
        float nodata_value = string::extract_float_value_from_string(point_data_pointer, (char*) " \n", (const char*) "nodata_value");

        uint32_t image_width_in_use = 3000; // should be 3000.
        uint32_t image_height_in_use = 2000;

        float* vertex_data;
        vertex_data = new float[image_width_in_use * image_height_in_use];

        float* vertex_pointer;
        vertex_pointer = vertex_data;

        // start processing image_data.

        for (uint32_t z = 0; z < image_height_in_use; z++)
        {
            for (uint32_t x = 0; x < image_width_in_use; x++)
            {
                while (!string::check_and_report_if_some_string_matches(point_data, point_data_pointer, number_strings_vector))
                {
                    point_data_pointer++;
                }
                *vertex_pointer++ = string::extract_float_value_from_string(point_data_pointer, (char*) " \n", (const char*) nullptr);
            }
        }

        delete point_data;

        std::cout << "Triangulating ascii grid data.\n";

        TriangulateQuadsStruct triangulate_quads_struct;
        // triangulate_quads_struct.image_width = image_width;
        triangulate_quads_struct.image_width = image_width_in_use;
        triangulate_quads_struct.image_height = image_height_in_use;
        triangulate_quads_struct.triangulation_type = triangulation_type;
        triangulate_quads_struct.sphere_radius = NAN;
        triangulate_quads_struct.spherical_world_struct = SphericalWorldStruct(); // not used, but is needed in the function call.

        bool result = geometry::triangulate_quads(vertex_data, triangulate_quads_struct, out_vertices, out_UVs, out_normals);
        delete vertex_data;
        return true;
    }
}
<|endoftext|>


<commit_before>#include "symbiont_species.hpp"
#include "vboindexer.hpp"
#include "universe.hpp"
#include "scene.hpp"
#include "shader.hpp"
#include "symbiont_material.hpp"
#include "biont.hpp"
#include "object.hpp"
#include "species_or_glyph.hpp"
#include "render_templates.hpp"
#include "code/ylikuutio/hierarchy/hierarchy_templates.hpp"

// Include GLEW
#ifndef __GL_GLEW_H_INCLUDED
#define __GL_GLEW_H_INCLUDED
#include <GL/glew.h> // GLfloat, GLuint etc.
#endif

// Include standard headers
#include <cstddef>  // std::size_t
#include <iostream> // std::cout, std::cin, std::cerr

namespace yli
{
    namespace ontology
    {
        void SymbiontSpecies::bind_biont(yli::ontology::Biont* const biont)
        {
            // `SymbiontSpecies` is not the ontological parent of `Biont`,
            // as `Holobiont` is the ontological parent of `Biont`.
            // The relationship between `SymbiontSpecies` and `Biont`
            // is purely only for rendering.
            //
            // To avoid potential problems in the future, follow this order:
            // 1. bind `Biont` to its `Holobiont` parent.
            // 2. bind `Biont` to its corresponding `SymbiontSpecies`.
            // 3. do stuff
            // 4. unbind `Biont` from its `SymbiontSpecies`.
            // 5. unbind `Biont` from its `Holobiont` parent.
            //
            // get `childID` from `SymbiontSpecies` and set pointer to `biont`.
            yli::hierarchy::bind_child_to_parent<yli::ontology::Biont*>(
                    biont,
                    this->biont_pointer_vector,
                    this->free_biontID_queue,
                    this->number_of_bionts);
        }

        void SymbiontSpecies::unbind_biont(const std::size_t childID)
        {
            yli::hierarchy::unbind_child_from_parent(
                    childID,
                    this->biont_pointer_vector,
                    this->free_biontID_queue,
                    this->number_of_bionts);
        }

        void SymbiontSpecies::bind_to_parent()
        {
            // requirements:
            // `this->symbiont_material_parent` must not be `nullptr`.
            yli::ontology::SymbiontMaterial* const symbiont_material = this->symbiont_material_parent;

            if (symbiont_material == nullptr)
            {
                std::cerr << "ERROR: `SymbiontSpecies::bind_to_parent`: `symbiont_material` is `nullptr`!\n";
                return;
            }

            // get `childID` from `SymbiontMaterial` and set pointer to this `SymbiontSpecies`.
            symbiont_material->bind_symbiont_species(this);
        }

        SymbiontSpecies::~SymbiontSpecies()
        {
            // destructor.
            std::cout << "SymbiontSpecies with childID " << std::dec << this->childID << " will be destroyed.\n";

            if (this->vram_buffer_in_use)
            {
                glDeleteBuffers(1, &this->normalbuffer);
                glDeleteBuffers(1, &this->elementbuffer);
            }

            // requirements for further actions:
            // `this->symbiont_material_parent` must not be `nullptr`.

            yli::ontology::SymbiontMaterial* const symbiont_material = this->symbiont_material_parent;

            // set pointer to this `SymbiontSpecies` to `nullptr`.
            if (symbiont_material == nullptr)
            {
                std::cerr << "ERROR: `SymbiontSpecies::~SymbiontSpecies`: `symbiont_material` is `nullptr`!\n";
                return;
            }

            symbiont_material->unbind_symbiont_species(this->childID);
        }

        void SymbiontSpecies::render()
        {
            this->prerender();

            // render this `SymbiontSpecies`.
            yli::ontology::render_species_or_glyph<yli::ontology::SymbiontSpecies*>(this);

            this->postrender();
        }

        yli::ontology::Entity* SymbiontSpecies::get_parent() const
        {
            return this->symbiont_material_parent;
        }

        std::size_t SymbiontSpecies::get_indices_size() const
        {
            return this->indices.size();
        }

        GLuint SymbiontSpecies::get_lightID() const
        {
            return this->lightID;
        }
    }
}
<commit_msg>`SymbiontSpecies::render`: render only if VRAM buffer in use.<commit_after>#include "symbiont_species.hpp"
#include "vboindexer.hpp"
#include "universe.hpp"
#include "scene.hpp"
#include "shader.hpp"
#include "symbiont_material.hpp"
#include "biont.hpp"
#include "object.hpp"
#include "species_or_glyph.hpp"
#include "render_templates.hpp"
#include "code/ylikuutio/hierarchy/hierarchy_templates.hpp"

// Include GLEW
#ifndef __GL_GLEW_H_INCLUDED
#define __GL_GLEW_H_INCLUDED
#include <GL/glew.h> // GLfloat, GLuint etc.
#endif

// Include standard headers
#include <cstddef>  // std::size_t
#include <iostream> // std::cout, std::cin, std::cerr

namespace yli
{
    namespace ontology
    {
        void SymbiontSpecies::bind_biont(yli::ontology::Biont* const biont)
        {
            // `SymbiontSpecies` is not the ontological parent of `Biont`,
            // as `Holobiont` is the ontological parent of `Biont`.
            // The relationship between `SymbiontSpecies` and `Biont`
            // is purely only for rendering.
            //
            // To avoid potential problems in the future, follow this order:
            // 1. bind `Biont` to its `Holobiont` parent.
            // 2. bind `Biont` to its corresponding `SymbiontSpecies`.
            // 3. do stuff
            // 4. unbind `Biont` from its `SymbiontSpecies`.
            // 5. unbind `Biont` from its `Holobiont` parent.
            //
            // get `childID` from `SymbiontSpecies` and set pointer to `biont`.
            yli::hierarchy::bind_child_to_parent<yli::ontology::Biont*>(
                    biont,
                    this->biont_pointer_vector,
                    this->free_biontID_queue,
                    this->number_of_bionts);
        }

        void SymbiontSpecies::unbind_biont(const std::size_t childID)
        {
            yli::hierarchy::unbind_child_from_parent(
                    childID,
                    this->biont_pointer_vector,
                    this->free_biontID_queue,
                    this->number_of_bionts);
        }

        void SymbiontSpecies::bind_to_parent()
        {
            // requirements:
            // `this->symbiont_material_parent` must not be `nullptr`.
            yli::ontology::SymbiontMaterial* const symbiont_material = this->symbiont_material_parent;

            if (symbiont_material == nullptr)
            {
                std::cerr << "ERROR: `SymbiontSpecies::bind_to_parent`: `symbiont_material` is `nullptr`!\n";
                return;
            }

            // get `childID` from `SymbiontMaterial` and set pointer to this `SymbiontSpecies`.
            symbiont_material->bind_symbiont_species(this);
        }

        SymbiontSpecies::~SymbiontSpecies()
        {
            // destructor.
            std::cout << "SymbiontSpecies with childID " << std::dec << this->childID << " will be destroyed.\n";

            if (this->vram_buffer_in_use)
            {
                glDeleteBuffers(1, &this->normalbuffer);
                glDeleteBuffers(1, &this->elementbuffer);
            }

            // requirements for further actions:
            // `this->symbiont_material_parent` must not be `nullptr`.

            yli::ontology::SymbiontMaterial* const symbiont_material = this->symbiont_material_parent;

            // set pointer to this `SymbiontSpecies` to `nullptr`.
            if (symbiont_material == nullptr)
            {
                std::cerr << "ERROR: `SymbiontSpecies::~SymbiontSpecies`: `symbiont_material` is `nullptr`!\n";
                return;
            }

            symbiont_material->unbind_symbiont_species(this->childID);
        }

        void SymbiontSpecies::render()
        {
            if (this->vram_buffer_in_use)
            {
                this->prerender();

                // render this `SymbiontSpecies`.
                yli::ontology::render_species_or_glyph<yli::ontology::SymbiontSpecies*>(this);

                this->postrender();
            }
        }

        yli::ontology::Entity* SymbiontSpecies::get_parent() const
        {
            return this->symbiont_material_parent;
        }

        std::size_t SymbiontSpecies::get_indices_size() const
        {
            return this->indices.size();
        }

        GLuint SymbiontSpecies::get_lightID() const
        {
            return this->lightID;
        }
    }
}
<|endoftext|>