<commit_before>// $Id$

// The libMesh Finite Element Library.
// Copyright (C) 2002-2008 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// This library is free software; you can redistribute 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.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// library configuration
#include "libmesh_config.h"

// C++ includes
#include <algorithm> // for std::min
#include <map>       // for std::multimap
#include <sstream>   // for std::ostringstream

// Local includes
#include "boundary_info.h"
#include "elem.h"
#include "mesh_base.h"
#include "mesh_tools.h"
#include "partitioner.h"
#include "point_locator_base.h"

// ------------------------------------------------------------
// MeshBase class member functions
MeshBase::MeshBase (unsigned int d) :
  boundary_info  (new BoundaryInfo(*this)),
  _n_sbd         (1),
  _n_parts       (1),
  _dim           (d),
  _is_prepared   (false),
  _point_locator (NULL),
  _partitioner   (NULL)
{
  libmesh_assert (LIBMESH_DIM <= 3);
  libmesh_assert (LIBMESH_DIM >= _dim);
  libmesh_assert (libMesh::initialized());
}

MeshBase::MeshBase (const MeshBase& other_mesh) :
  boundary_info  (new BoundaryInfo(*this)), // no copy constructor defined for BoundaryInfo?
  _n_sbd         (other_mesh._n_sbd),
  _n_parts       (other_mesh._n_parts),
  _dim           (other_mesh._dim),
  _is_prepared   (other_mesh._is_prepared),
  _point_locator (NULL),
  _partitioner   (NULL)
{
}

MeshBase::~MeshBase()
{
  this->clear();

  libmesh_assert (!libMesh::closed());
}

void MeshBase::prepare_for_use (const bool skip_renumber_nodes_and_elements)
{
  // Renumber the nodes and elements so that they in contiguous
  // blocks.  By default, skip_renumber_nodes_and_elements is false,
  // however we may skip this step by passing
  // skip_renumber_nodes_and_elements==true to this function.
  //
  // Instances where you if prepare_for_use() should not renumber the nodes
  // and elements include reading in e.g. an xda/r or gmv file. In
  // this case, the ordering of the nodes may depend on an accompanying
  // solution, and the node ordering cannot be changed.
  if(!skip_renumber_nodes_and_elements)
    this->renumber_nodes_and_elements();

  // Let all the elements find their neighbors
  this->find_neighbors();

  // Partition the mesh.
  this->partition();

  // If we're using ParallelMesh, we'll want it parallelized.
  this->delete_remote_elements();

  if(!skip_renumber_nodes_and_elements)
    this->renumber_nodes_and_elements();

  // Reset our PointLocator.  This needs to happen any time the elements
  // in the underlying elements in the mesh have changed, so we do it here.
  this->clear_point_locator();

  // The mesh is now prepared for use.
  _is_prepared = true;
}

unsigned int MeshBase::n_active_elem () const
{
  return static_cast<unsigned int>(std::distance (this->active_elements_begin(),
						  this->active_elements_end()));
}

void MeshBase::clear ()
{

  // Reset the number of subdomains
  _n_sbd  = 1;

  // Reset the number of partitions
  _n_parts = 1;

  // Reset the _is_prepared flag
  _is_prepared = false;

  // Clear boundary information
  this->boundary_info->clear();

  // Clear our point locator.
  this->clear_point_locator();
}

unsigned int MeshBase::n_nodes_on_proc (const unsigned int proc_id) const
{
  // We're either counting a processor's nodes or unpartitioned
  // nodes
  libmesh_assert (proc_id < libMesh::n_processors() ||
	  proc_id == DofObject::invalid_processor_id);

  return static_cast<unsigned int>(std::distance (this->pid_nodes_begin(proc_id),
						  this->pid_nodes_end  (proc_id)));
}

unsigned int MeshBase::n_elem_on_proc (const unsigned int proc_id) const
{
  // We're either counting a processor's elements or unpartitioned
  // elements
  libmesh_assert (proc_id < libMesh::n_processors() ||
	  proc_id == DofObject::invalid_processor_id);

  return static_cast<unsigned int>(std::distance (this->pid_elements_begin(proc_id),
						  this->pid_elements_end  (proc_id)));
}

unsigned int MeshBase::n_active_elem_on_proc (const unsigned int proc_id) const
{
  libmesh_assert (proc_id < libMesh::n_processors());
  return static_cast<unsigned int>(std::distance (this->active_pid_elements_begin(proc_id),
						  this->active_pid_elements_end  (proc_id)));
}

unsigned int MeshBase::n_sub_elem () const
{
  unsigned int ne=0;

  const_element_iterator       el  = this->elements_begin();
  const const_element_iterator end = this->elements_end();

  for (; el!=end; ++el)
    ne += (*el)->n_sub_elem();

  return ne;
}

unsigned int MeshBase::n_active_sub_elem () const
{
  unsigned int ne=0;

  const_element_iterator       el  = this->active_elements_begin();
  const const_element_iterator end = this->active_elements_end();

  for (; el!=end; ++el)
    ne += (*el)->n_sub_elem();

  return ne;
}

std::string MeshBase::get_info() const
{
  std::ostringstream out;

  out << " Mesh Information:"                                  << '\n'
      << "  mesh_dimension()="    << this->mesh_dimension()    << '\n'
      << "  spatial_dimension()=" << this->spatial_dimension() << '\n'
      << "  n_nodes()="           << this->n_nodes()           << '\n'
      << "    n_local_nodes()="   << this->n_local_nodes()     << '\n'
      << "  n_elem()="            << this->n_elem()            << '\n'
      << "    n_local_elem()="    << this->n_local_elem()      << '\n'
#ifdef LIBMESH_ENABLE_AMR
      << "    n_active_elem()="   << this->n_active_elem()     << '\n'
#endif
      << "  n_subdomains()="      << this->n_subdomains()      << '\n'
      << "  n_processors()="      << this->n_processors()      << '\n'
      << "  processor_id()="      << this->processor_id()      << '\n';

  return out.str();
}

void MeshBase::print_info(std::ostream& os) const
{
  os << this->get_info()
     << std::endl;
}

std::ostream& operator << (std::ostream& os, const MeshBase& m)
{
  m.print_info(os);
  return os;
}

void MeshBase::partition (const unsigned int n_parts)
{
  partitioner()->partition (*this, n_parts);
}

unsigned int MeshBase::recalculate_n_partitions()
{
  const_element_iterator       el  = this->active_elements_begin();
  const const_element_iterator end = this->active_elements_end();

  unsigned int max_proc_id=0;

  for (; el!=end; ++el)
    max_proc_id = std::max(max_proc_id, static_cast<unsigned int>((*el)->processor_id()));

  // The number of partitions is one more than the max processor ID.
  _n_parts = max_proc_id+1;

  return _n_parts;
}

const PointLocatorBase & MeshBase::point_locator () const
{
  if (_point_locator.get() == NULL)
    _point_locator.reset (PointLocatorBase::build(TREE, *this).release());

  return *_point_locator;
}

void MeshBase::clear_point_locator ()
{
  _point_locator.reset(NULL);
}

<commit_msg>Don't try to partition when the user has disabled the partitioner<commit_after>// $Id$

// The libMesh Finite Element Library.
// Copyright (C) 2002-2008 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// This library is free software; you can redistribute 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.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// library configuration
#include "libmesh_config.h"

// C++ includes
#include <algorithm> // for std::min
#include <map>       // for std::multimap
#include <sstream>   // for std::ostringstream

// Local includes
#include "boundary_info.h"
#include "elem.h"
#include "mesh_base.h"
#include "mesh_tools.h"
#include "partitioner.h"
#include "point_locator_base.h"

// ------------------------------------------------------------
// MeshBase class member functions
MeshBase::MeshBase (unsigned int d) :
  boundary_info  (new BoundaryInfo(*this)),
  _n_sbd         (1),
  _n_parts       (1),
  _dim           (d),
  _is_prepared   (false),
  _point_locator (NULL),
  _partitioner   (NULL)
{
  libmesh_assert (LIBMESH_DIM <= 3);
  libmesh_assert (LIBMESH_DIM >= _dim);
  libmesh_assert (libMesh::initialized());
}

MeshBase::MeshBase (const MeshBase& other_mesh) :
  boundary_info  (new BoundaryInfo(*this)), // no copy constructor defined for BoundaryInfo?
  _n_sbd         (other_mesh._n_sbd),
  _n_parts       (other_mesh._n_parts),
  _dim           (other_mesh._dim),
  _is_prepared   (other_mesh._is_prepared),
  _point_locator (NULL),
  _partitioner   (NULL)
{
}

MeshBase::~MeshBase()
{
  this->clear();

  libmesh_assert (!libMesh::closed());
}

void MeshBase::prepare_for_use (const bool skip_renumber_nodes_and_elements)
{
  // Renumber the nodes and elements so that they in contiguous
  // blocks.  By default, skip_renumber_nodes_and_elements is false,
  // however we may skip this step by passing
  // skip_renumber_nodes_and_elements==true to this function.
  //
  // Instances where you if prepare_for_use() should not renumber the nodes
  // and elements include reading in e.g. an xda/r or gmv file. In
  // this case, the ordering of the nodes may depend on an accompanying
  // solution, and the node ordering cannot be changed.
  if(!skip_renumber_nodes_and_elements)
    this->renumber_nodes_and_elements();

  // Let all the elements find their neighbors
  this->find_neighbors();

  // Partition the mesh.
  this->partition();

  // If we're using ParallelMesh, we'll want it parallelized.
  this->delete_remote_elements();

  if(!skip_renumber_nodes_and_elements)
    this->renumber_nodes_and_elements();

  // Reset our PointLocator.  This needs to happen any time the elements
  // in the underlying elements in the mesh have changed, so we do it here.
  this->clear_point_locator();

  // The mesh is now prepared for use.
  _is_prepared = true;
}

unsigned int MeshBase::n_active_elem () const
{
  return static_cast<unsigned int>(std::distance (this->active_elements_begin(),
						  this->active_elements_end()));
}

void MeshBase::clear ()
{

  // Reset the number of subdomains
  _n_sbd  = 1;

  // Reset the number of partitions
  _n_parts = 1;

  // Reset the _is_prepared flag
  _is_prepared = false;

  // Clear boundary information
  this->boundary_info->clear();

  // Clear our point locator.
  this->clear_point_locator();
}

unsigned int MeshBase::n_nodes_on_proc (const unsigned int proc_id) const
{
  // We're either counting a processor's nodes or unpartitioned
  // nodes
  libmesh_assert (proc_id < libMesh::n_processors() ||
	  proc_id == DofObject::invalid_processor_id);

  return static_cast<unsigned int>(std::distance (this->pid_nodes_begin(proc_id),
						  this->pid_nodes_end  (proc_id)));
}

unsigned int MeshBase::n_elem_on_proc (const unsigned int proc_id) const
{
  // We're either counting a processor's elements or unpartitioned
  // elements
  libmesh_assert (proc_id < libMesh::n_processors() ||
	  proc_id == DofObject::invalid_processor_id);

  return static_cast<unsigned int>(std::distance (this->pid_elements_begin(proc_id),
						  this->pid_elements_end  (proc_id)));
}

unsigned int MeshBase::n_active_elem_on_proc (const unsigned int proc_id) const
{
  libmesh_assert (proc_id < libMesh::n_processors());
  return static_cast<unsigned int>(std::distance (this->active_pid_elements_begin(proc_id),
						  this->active_pid_elements_end  (proc_id)));
}

unsigned int MeshBase::n_sub_elem () const
{
  unsigned int ne=0;

  const_element_iterator       el  = this->elements_begin();
  const const_element_iterator end = this->elements_end();

  for (; el!=end; ++el)
    ne += (*el)->n_sub_elem();

  return ne;
}

unsigned int MeshBase::n_active_sub_elem () const
{
  unsigned int ne=0;

  const_element_iterator       el  = this->active_elements_begin();
  const const_element_iterator end = this->active_elements_end();

  for (; el!=end; ++el)
    ne += (*el)->n_sub_elem();

  return ne;
}

std::string MeshBase::get_info() const
{
  std::ostringstream out;

  out << " Mesh Information:"                                  << '\n'
      << "  mesh_dimension()="    << this->mesh_dimension()    << '\n'
      << "  spatial_dimension()=" << this->spatial_dimension() << '\n'
      << "  n_nodes()="           << this->n_nodes()           << '\n'
      << "    n_local_nodes()="   << this->n_local_nodes()     << '\n'
      << "  n_elem()="            << this->n_elem()            << '\n'
      << "    n_local_elem()="    << this->n_local_elem()      << '\n'
#ifdef LIBMESH_ENABLE_AMR
      << "    n_active_elem()="   << this->n_active_elem()     << '\n'
#endif
      << "  n_subdomains()="      << this->n_subdomains()      << '\n'
      << "  n_processors()="      << this->n_processors()      << '\n'
      << "  processor_id()="      << this->processor_id()      << '\n';

  return out.str();
}

void MeshBase::print_info(std::ostream& os) const
{
  os << this->get_info()
     << std::endl;
}

std::ostream& operator << (std::ostream& os, const MeshBase& m)
{
  m.print_info(os);
  return os;
}

void MeshBase::partition (const unsigned int n_parts)
{
  if (partitioner().get()) // "NULL" means don't partition
    partitioner()->partition (*this, n_parts);
}

unsigned int MeshBase::recalculate_n_partitions()
{
  const_element_iterator       el  = this->active_elements_begin();
  const const_element_iterator end = this->active_elements_end();

  unsigned int max_proc_id=0;

  for (; el!=end; ++el)
    max_proc_id = std::max(max_proc_id, static_cast<unsigned int>((*el)->processor_id()));

  // The number of partitions is one more than the max processor ID.
  _n_parts = max_proc_id+1;

  return _n_parts;
}

const PointLocatorBase & MeshBase::point_locator () const
{
  if (_point_locator.get() == NULL)
    _point_locator.reset (PointLocatorBase::build(TREE, *this).release());

  return *_point_locator;
}

void MeshBase::clear_point_locator ()
{
  _point_locator.reset(NULL);
}

<|endoftext|>


<commit_before>#include "player.h"
#include "json.h"
#include <iostream>
const char* Player::VERSION = "Default C++ folding player";

int Player::betRequest(json::Value game_state)
{
    std::cerr<<json::Serialize(game_state);
    return 100;
}

void Player::showdown(json::Value game_state)
{
}
<commit_msg>parse log<commit_after>#include "player.h"
#include "json.h"
#include <iostream>
const char* Player::VERSION = "Default C++ folding player";

int Player::betRequest(json::Value game_state)
{
    std::cerr<<json::Serialize(game_state)<<std::endl;
    std::string s = json::Serialize(game_state);
    std::string delimiter = "{";
    std::string token;
    size_t pos = 0;
    while ((pos = s.find(delimiter)) != std::string::npos) {
        token = s.substr(0,pos);
        std::cout << token << std::endl;
        s.erase(0, pos + delimiter.length());
    }
    return 100;

}

void Player::showdown(json::Value game_state)
{
}
<|endoftext|>


<commit_before>//  Copyright 2016 Peter Georg
//
//  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 "benchmark.hpp"
#include <array>
#include <sstream>
#include <algorithm>
extern "C"
{
#include <omp.h>
}
#include "parameter.hpp"
#include "mpi.hpp"
#include "../misc/allocator.hpp"
#include "../misc/time.hpp"
#include "communicator.hpp"
#include "connection.hpp"
#include "sendwindow.hpp"
#include "recvwindow.hpp"
#include "allreduce.hpp"
#include "reduce.hpp"

void runBenchmark(int argc, char **argv)
{
    // Default options
    int dim = 1;
    std::vector<int> geom;
    std::vector<int> periodic;
    std::uint64_t maxIter = 1e4;
    std::uint64_t overallSize = 1024 * 1024 * 1024;
    std::uint32_t minMsgSize = 0;
    std::uint32_t maxMsgSize = 128 * 1024;
    std::uint32_t deltaMsgSize = 4 * 1024;
    std::uint32_t granularity = 4;
    bool bufferedSend = false;
    bool bufferedRecv = false;

    // Get additional parameter options
    parameterOption(argv, argv + argc, "--dim", dim);
    geom.resize(dim, 0);
    periodic.resize(dim, 1);
    parameterOption(argv, argv + argc, "--geom", geom);
    parameterOption(argv, argv + argc, "--periodic", periodic);
    parameterOption<std::uint64_t>(argv, argv + argc, "--maxIter", maxIter);
    parameterOption<std::uint64_t>(argv, argv + argc, "--overallSize",
            overallSize);
    parameterOption<std::uint32_t>(argv, argv + argc, "--minMsgSize",
            minMsgSize);
    parameterOption<std::uint32_t>(argv, argv + argc, "--maxMsgSize",
            maxMsgSize);
    parameterOption<std::uint32_t>(argv, argv + argc, "--deltaMsgSize",
            deltaMsgSize);
    parameterOption<std::uint32_t>(argv, argv + argc, "--granularity",
            granularity);
    if(parameterExists(argv, argv + argc, "--bufferedSend"))
    {
        bufferedSend = true;
    }
    if(parameterExists(argv, argv + argc, "--bufferedRecv"))
    {
        bufferedRecv = true;
    }

    // Prepare benchmark environment
    pMR::Communicator communicator(MPI_COMM_WORLD, geom, periodic);

    std::string benchmark;
    parameterOption<std::string>(argv, argv + argc, "--benchmark", benchmark);
    if(benchmark == "allreduce")
    {
        // Print Benchmark Information
        printMaster("Benchmark:   ", benchmark);
        printMaster("Processes:   ", communicator.size());
        printMaster();

        printMaster(" MPIRank Size[By] WSize[By] Iteration  Time/It[s]");

        deltaMsgSize = (deltaMsgSize / sizeof(float)) * sizeof(float);
        if(deltaMsgSize == 0)
        {
            deltaMsgSize += sizeof(float);
        }

        // Loop Message Sizes
        auto msgSize = minMsgSize;
        while(msgSize <= maxMsgSize)
        {
            msgSize = (msgSize / sizeof(float)) * sizeof(float);
            // Calculate iterations count
            auto iter = maxIter;
            if(msgSize)
            {
                iter = std::min(iter, overallSize / msgSize /
                        static_cast<std::uint64_t>(communicator.size()));
            }

            pMR::AllReduce allReduce(communicator,
                    std::ceil(static_cast<double>(msgSize) / granularity) *
                    granularity);

            std::vector<float> vSum;
            vSum.resize(msgSize / sizeof(float));
            double time = -pMR::getTimeInSeconds();
            for(decltype(iter) i = 0; i != iter; ++i)
            {
                allReduce.insert<float>(vSum.cbegin(), msgSize / sizeof(float));
                allReduce.execute(&plus, msgSize / sizeof(float));
                allReduce.extract<float>(vSum.begin(), msgSize / sizeof(float));
            }
            time += pMR::getTimeInSeconds();
            pMR::print(static_cast<std::uint32_t>(getRank(MPI_COMM_WORLD)),
                    msgSize, allReduce.size<unsigned char>(),
                    iter, time / iter);
            msgSize += deltaMsgSize;
        }

        // Exit application
        finalize();
    }
    if(benchmark != "exchange" and benchmark != "sendrecv")
    {
        printUsage();
    }

    // Establish connections
    std::vector<pMR::Connection> connections;

    for(int n = 0; n != communicator.dimensions(); ++n)
    {
        if(communicator.size(n) > 1)
        {
            if(communicator.coordinate(n) % 2 == 1)
            {
                connections.emplace_back(communicator.getNeighbor(n, -1));
                connections.emplace_back(communicator.getNeighbor(n, +1));
            }
            else
            {
                connections.emplace_back(communicator.getNeighbor(n, +1));
                connections.emplace(connections.end() - 1,
                        communicator.getNeighbor(n, -1));
            }
        }
    }

    // Print Benchmark Information
    printMaster("Benchmark:   ", benchmark);
    printMaster("Processes:   ", communicator.size());
    printMaster("Dimensions:  ", static_cast<int>(connections.size()/2), "/",
            communicator.dimensions());
    printMaster("Topology:    ", communicator.topology());
    printMaster("Periodic:    ", communicator.periodic());
    printMaster("BufferedSend:", bufferedSend);
    printMaster("BufferedRecv:", bufferedRecv);
    printMaster();

    printMaster(" MPIRank Size[By] Iteration  Time/It[s] Bandwidth[MB/s]");

    // Loop Message Sizes
    auto msgSize = minMsgSize;
    while(msgSize <= maxMsgSize)
    {
        std::vector<std::vector<unsigned char,
            pMR::AlignedAllocator<unsigned char>>> sendBuffers, recvBuffers;
        std::vector<pMR::SendWindow<unsigned char>> sendWindows;
        std::vector<pMR::RecvWindow<unsigned char>> recvWindows;

        // Create Buffers and Windows
        for(decltype(connections.size()) c = 0; c != connections.size(); ++c)
        {
            sendBuffers.emplace_back(msgSize);
            if(bufferedSend)
            {
                sendWindows.emplace_back(connections[c], msgSize);
            }
            else
            {
                sendWindows.emplace_back(connections[c],
                        sendBuffers.back().data(), msgSize);
            }

            if(benchmark == "sendrecv")
            {
                ++c;
            }

            recvBuffers.emplace_back(msgSize);
            if(bufferedRecv)
            {
                recvWindows.emplace_back(connections[c], msgSize);
            }
            else
            {
                recvWindows.emplace_back(connections[c],
                        recvBuffers.back().data(), msgSize);
            }
        }

        // Go to next loop if nothing to do
        if(sendWindows.size() == 0 and recvWindows.size() == 0)
        {
            // Increment msgSize for next loop
            msgSize += deltaMsgSize;
            continue;
        }

        // Calculate iterations count
        auto iter = maxIter;
        if(msgSize)
        {
            iter = std::min(iter, overallSize / msgSize /
                    static_cast<std::uint64_t>(sendWindows.size()));
        }

        double time = -pMR::getTimeInSeconds();
        for(decltype(iter) i = 0; i != iter; ++i)
        {
            for(auto &recvWindow : recvWindows)
            {
                recvWindow.init();
            }
            for(auto &sendWindow : sendWindows)
            {
                sendWindow.init();
            }
            if(bufferedSend)
            {
                for(decltype(sendWindows.size()) s = 0; s != sendWindows.size();
                        ++s)
                {
                    sendWindows[s].insert(sendBuffers[s].cbegin());
                }
            }
            for(auto &sendWindow : sendWindows)
            {
                sendWindow.post();
            }
            for(auto &recvWindow : recvWindows)
            {
                recvWindow.post();
            }
            for(auto &sendWindow : sendWindows)
            {
                sendWindow.wait();
            }
            for(auto &recvWindow : recvWindows)
            {
                recvWindow.wait();
            }
            if(bufferedRecv)
            {
                for(decltype(recvWindows.size()) r = 0; r != recvWindows.size();
                        ++r)
                {
                    recvWindows[r].extract(recvBuffers[r].begin());
                }
            }

        }
        time += pMR::getTimeInSeconds();
        pMR::print(static_cast<std::uint32_t>(getRank(MPI_COMM_WORLD)),
                msgSize, iter, time / iter,
                msgSize * iter * sendWindows.size() / time / 1024 / 1024 );

        // Increment msgSize for next loop
        msgSize += deltaMsgSize;
    }

    // Exit application
    finalize();
}
<commit_msg>Report correct bandwidth for non-periodic topology<commit_after>//  Copyright 2016 Peter Georg
//
//  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 "benchmark.hpp"
#include <array>
#include <sstream>
#include <algorithm>
extern "C"
{
#include <omp.h>
}
#include "parameter.hpp"
#include "mpi.hpp"
#include "../misc/allocator.hpp"
#include "../misc/time.hpp"
#include "communicator.hpp"
#include "connection.hpp"
#include "sendwindow.hpp"
#include "recvwindow.hpp"
#include "allreduce.hpp"
#include "reduce.hpp"

void runBenchmark(int argc, char **argv)
{
    // Default options
    int dim = 1;
    std::vector<int> geom;
    std::vector<int> periodic;
    std::uint64_t maxIter = 1e4;
    std::uint64_t overallSize = 1024 * 1024 * 1024;
    std::uint32_t minMsgSize = 0;
    std::uint32_t maxMsgSize = 128 * 1024;
    std::uint32_t deltaMsgSize = 4 * 1024;
    std::uint32_t granularity = 4;
    bool bufferedSend = false;
    bool bufferedRecv = false;

    // Get additional parameter options
    parameterOption(argv, argv + argc, "--dim", dim);
    geom.resize(dim, 0);
    periodic.resize(dim, 1);
    parameterOption(argv, argv + argc, "--geom", geom);
    parameterOption(argv, argv + argc, "--periodic", periodic);
    parameterOption<std::uint64_t>(argv, argv + argc, "--maxIter", maxIter);
    parameterOption<std::uint64_t>(argv, argv + argc, "--overallSize",
            overallSize);
    parameterOption<std::uint32_t>(argv, argv + argc, "--minMsgSize",
            minMsgSize);
    parameterOption<std::uint32_t>(argv, argv + argc, "--maxMsgSize",
            maxMsgSize);
    parameterOption<std::uint32_t>(argv, argv + argc, "--deltaMsgSize",
            deltaMsgSize);
    parameterOption<std::uint32_t>(argv, argv + argc, "--granularity",
            granularity);
    if(parameterExists(argv, argv + argc, "--bufferedSend"))
    {
        bufferedSend = true;
    }
    if(parameterExists(argv, argv + argc, "--bufferedRecv"))
    {
        bufferedRecv = true;
    }

    // Prepare benchmark environment
    pMR::Communicator communicator(MPI_COMM_WORLD, geom, periodic);

    std::string benchmark;
    parameterOption<std::string>(argv, argv + argc, "--benchmark", benchmark);
    if(benchmark == "allreduce")
    {
        // Print Benchmark Information
        printMaster("Benchmark:   ", benchmark);
        printMaster("Processes:   ", communicator.size());
        printMaster();

        printMaster(" MPIRank Size[By] WSize[By] Iteration  Time/It[s]");

        deltaMsgSize = (deltaMsgSize / sizeof(float)) * sizeof(float);
        if(deltaMsgSize == 0)
        {
            deltaMsgSize += sizeof(float);
        }

        // Loop Message Sizes
        auto msgSize = minMsgSize;
        while(msgSize <= maxMsgSize)
        {
            msgSize = (msgSize / sizeof(float)) * sizeof(float);
            // Calculate iterations count
            auto iter = maxIter;
            if(msgSize)
            {
                iter = std::min(iter, overallSize / msgSize /
                        static_cast<std::uint64_t>(communicator.size()));
            }

            pMR::AllReduce allReduce(communicator,
                    std::ceil(static_cast<double>(msgSize) / granularity) *
                    granularity);

            std::vector<float> vSum;
            vSum.resize(msgSize / sizeof(float));
            double time = -pMR::getTimeInSeconds();
            for(decltype(iter) i = 0; i != iter; ++i)
            {
                allReduce.insert<float>(vSum.cbegin(), msgSize / sizeof(float));
                allReduce.execute(&plus, msgSize / sizeof(float));
                allReduce.extract<float>(vSum.begin(), msgSize / sizeof(float));
            }
            time += pMR::getTimeInSeconds();
            pMR::print(static_cast<std::uint32_t>(getRank(MPI_COMM_WORLD)),
                    msgSize, allReduce.size<unsigned char>(),
                    iter, time / iter);
            msgSize += deltaMsgSize;
        }

        // Exit application
        finalize();
    }
    if(benchmark != "exchange" and benchmark != "sendrecv")
    {
        printUsage();
    }

    // Establish connections
    std::vector<pMR::Connection> connections;

    // Store number of real data transfers per iteration
    unsigned int nDataTransfers = 0;

    for(int n = 0; n != communicator.dimensions(); ++n)
    {
        if(communicator.size(n) > 1)
        {
            pMR::Target rNeighbor = communicator.getNeighbor(n, +1);
            pMR::Target lNeighbor = communicator.getNeighbor(n, -1);
            if(!lNeighbor.isNull())
            {
                ++nDataTransfers;
            }
            if(!rNeighbor.isNull())
            {
                ++nDataTransfers;
            }

            if(communicator.coordinate(n) % 2 == 1)
            {
                connections.emplace_back(lNeighbor);
                connections.emplace_back(rNeighbor);
            }
            else
            {
                connections.emplace_back(rNeighbor);
                connections.emplace(connections.end() - 1, lNeighbor);
            }
        }
    }

    // Print Benchmark Information
    printMaster("Benchmark:   ", benchmark);
    printMaster("Processes:   ", communicator.size());
    printMaster("Dimensions:  ", static_cast<int>(connections.size()/2), "/",
            communicator.dimensions());
    printMaster("Topology:    ", communicator.topology());
    printMaster("Periodic:    ", communicator.periodic());
    printMaster("BufferedSend:", bufferedSend);
    printMaster("BufferedRecv:", bufferedRecv);
    printMaster();

    printMaster(" MPIRank Size[By] Iteration  Time/It[s] Bandwidth[MB/s]");

    // Loop Message Sizes
    auto msgSize = minMsgSize;
    while(msgSize <= maxMsgSize)
    {
        std::vector<std::vector<unsigned char,
            pMR::AlignedAllocator<unsigned char>>> sendBuffers, recvBuffers;
        std::vector<pMR::SendWindow<unsigned char>> sendWindows;
        std::vector<pMR::RecvWindow<unsigned char>> recvWindows;

        // Create Buffers and Windows
        for(decltype(connections.size()) c = 0; c != connections.size(); ++c)
        {
            sendBuffers.emplace_back(msgSize);
            if(bufferedSend)
            {
                sendWindows.emplace_back(connections[c], msgSize);
            }
            else
            {
                sendWindows.emplace_back(connections[c],
                        sendBuffers.back().data(), msgSize);
            }

            if(benchmark == "sendrecv")
            {
                ++c;
            }

            recvBuffers.emplace_back(msgSize);
            if(bufferedRecv)
            {
                recvWindows.emplace_back(connections[c], msgSize);
            }
            else
            {
                recvWindows.emplace_back(connections[c],
                        recvBuffers.back().data(), msgSize);
            }
        }

        // Go to next loop if nothing to do
        if(sendWindows.size() == 0 and recvWindows.size() == 0)
        {
            // Increment msgSize for next loop
            msgSize += deltaMsgSize;
            continue;
        }

        // Calculate iterations count
        auto iter = maxIter;
        if(msgSize)
        {
            iter = std::min(iter, overallSize / msgSize /
                    static_cast<std::uint64_t>(sendWindows.size()));
        }

        double time = -pMR::getTimeInSeconds();
        for(decltype(iter) i = 0; i != iter; ++i)
        {
            for(auto &recvWindow : recvWindows)
            {
                recvWindow.init();
            }
            for(auto &sendWindow : sendWindows)
            {
                sendWindow.init();
            }
            if(bufferedSend)
            {
                for(decltype(sendWindows.size()) s = 0; s != sendWindows.size();
                        ++s)
                {
                    sendWindows[s].insert(sendBuffers[s].cbegin());
                }
            }
            for(auto &sendWindow : sendWindows)
            {
                sendWindow.post();
            }
            for(auto &recvWindow : recvWindows)
            {
                recvWindow.post();
            }
            for(auto &sendWindow : sendWindows)
            {
                sendWindow.wait();
            }
            for(auto &recvWindow : recvWindows)
            {
                recvWindow.wait();
            }
            if(bufferedRecv)
            {
                for(decltype(recvWindows.size()) r = 0; r != recvWindows.size();
                        ++r)
                {
                    recvWindows[r].extract(recvBuffers[r].begin());
                }
            }

        }
        time += pMR::getTimeInSeconds();
        pMR::print(static_cast<std::uint32_t>(getRank(MPI_COMM_WORLD)),
                msgSize, iter, time / iter,
                msgSize * iter * nDataTransfers / time / 1024 / 1024 );

        // Increment msgSize for next loop
        msgSize += deltaMsgSize;
    }

    // Exit application
    finalize();
}
<|endoftext|>


<commit_before>// $Id$
// Copyright Guido Kanschat, 1999

#include <grid/dof.h>
#include <grid/mg_dof.h>
#include <grid/dof_accessor.h>
#include <grid/mg_dof_accessor.h>
#include <grid/tria_iterator.h>
#include <fe/fe.h>
#include <fe/fe_system.h>
#include <basic/dof_tools.h>
#include <lac/sparsematrix.h>

#include <algorithm>

template <int dim>
void
DoFTools::make_sparsity_pattern (const DoFHandler<dim>& dof,
				 SparseMatrixStruct &sparsity)
{
  const unsigned int n_dofs = dof.n_dofs();

  Assert (sparsity.n_rows() == n_dofs,
	  ExcDimensionMismatch (sparsity.n_rows(), n_dofs));
  Assert (sparsity.n_cols() == n_dofs,
	  ExcDimensionMismatch (sparsity.n_cols(), n_dofs));

  const unsigned int dofs_per_cell = dof.get_fe().dofs_per_cell;
  vector<int> dofs_on_this_cell(dofs_per_cell);
  DoFHandler<dim>::active_cell_iterator cell = dof.begin_active(),
		       endc = dof.end();
  for (; cell!=endc; ++cell)
    {
      cell->get_dof_indices (dofs_on_this_cell);
				       // make sparsity pattern for this cell
      for (unsigned int i=0; i<dofs_per_cell; ++i)
	for (unsigned int j=0; j<dofs_per_cell; ++j)
	  sparsity.add (dofs_on_this_cell[i],
			dofs_on_this_cell[j]);
    }
}

template <int dim>
void
DoFTools::make_sparsity_pattern (const DoFHandler<dim>& dof,
					const vector<vector<bool> > &mask,
					SparseMatrixStruct          &sparsity)
{
  const unsigned int n_dofs = dof.n_dofs();
  const unsigned int dofs_per_cell = dof.get_fe().dofs_per_cell;

  Assert (sparsity.n_rows() == n_dofs,
	  ExcDimensionMismatch (sparsity.n_rows(), n_dofs));
  Assert (sparsity.n_cols() == n_dofs,
	  ExcDimensionMismatch (sparsity.n_cols(), n_dofs));
  Assert (mask.size() == dof.get_fe().n_components(),
	  ExcDimensionMismatch(mask.size(), dof.get_fe().n_components()));
  for (unsigned int i=0; i<mask.size(); ++i)
    Assert (mask[i].size() == dof.get_fe().n_components(),
	    ExcDimensionMismatch(mask[i].size(), dof.get_fe().n_components()));

				   // first build a mask for each dof,
				   // not like the one given which represents
				   // components
  vector<vector<bool> > dof_mask(dofs_per_cell,
				 vector<bool>(dofs_per_cell, false));
  for (unsigned int i=0; i<dofs_per_cell; ++i)
    for (unsigned int j=0; j<dofs_per_cell; ++j)
      dof_mask[i][j] = mask
		       [dof.get_fe().system_to_component_index(i).first]
		       [dof.get_fe().system_to_component_index(j).first];

  vector<int> dofs_on_this_cell(dofs_per_cell);
  DoFHandler<dim>::active_cell_iterator cell = dof.begin_active(),
		       endc = dof.end();
  for (; cell!=endc; ++cell)
    {
      cell->get_dof_indices (dofs_on_this_cell);
				       // make sparsity pattern for this cell
      for (unsigned int i=0; i<dofs_per_cell; ++i)
	for (unsigned int j=0; j<dofs_per_cell; ++j)
	  if (dof_mask[i][j] == true)
	    sparsity.add (dofs_on_this_cell[i],
			  dofs_on_this_cell[j]);
    }
}

#if deal_II_dimension == 1

template <>
void DoFTools::make_boundary_sparsity_pattern (const DoFHandler<1>&,
						    const vector<int>  &,
						    SparseMatrixStruct &)
{
    Assert (false, ExcInternalError());
};

template <>
void
DoFTools::make_boundary_sparsity_pattern (const DoFHandler<1>&,
					  const DoFHandler<1>::FunctionMap  &,
					  const vector<int>  &,
					  SparseMatrixStruct &)
{
  Assert (false, ExcInternalError());
}

#endif

template <int dim>
void
DoFTools::make_boundary_sparsity_pattern (const DoFHandler<dim>& dof,
					  const vector<int>  &dof_to_boundary_mapping,
					  SparseMatrixStruct &sparsity)
{
  const unsigned int n_dofs = dof.n_dofs();

  Assert (dof_to_boundary_mapping.size() == n_dofs, ExcInternalError());
  Assert (sparsity.n_rows() == dof.n_boundary_dofs(),
	  ExcDimensionMismatch (sparsity.n_rows(), dof.n_boundary_dofs()));
  Assert (sparsity.n_cols() == dof.n_boundary_dofs(),
	  ExcDimensionMismatch (sparsity.n_cols(), dof.n_boundary_dofs()));
  Assert (*max_element(dof_to_boundary_mapping.begin(),
		       dof_to_boundary_mapping.end()) == (signed int)sparsity.n_rows()-1,
	  ExcInternalError());

  const unsigned int dofs_per_face = dof.get_fe().dofs_per_face;
  vector<int> dofs_on_this_face(dofs_per_face);
  DoFHandler<dim>::active_face_iterator face = dof.begin_active_face(),
		       endf = dof.end_face();
  for (; face!=endf; ++face)
    if (face->at_boundary())
      {
	face->get_dof_indices (dofs_on_this_face);

					 // make sure all dof indices have a
					 // boundary index
	Assert (*min_element(dofs_on_this_face.begin(),
			     dofs_on_this_face.end()) >=0,
		ExcInternalError());

					 // make sparsity pattern for this cell
	for (unsigned int i=0; i<dofs_per_face; ++i)
	  for (unsigned int j=0; j<dofs_per_face; ++j)
	    sparsity.add (dof_to_boundary_mapping[dofs_on_this_face[i]],
			  dof_to_boundary_mapping[dofs_on_this_face[j]]);
      };
};

template <int dim>
void DoFTools::make_boundary_sparsity_pattern (const DoFHandler<dim>& dof,
					       const DoFHandler<dim>::FunctionMap  &boundary_indicators,
					       const vector<int>  &dof_to_boundary_mapping,
					       SparseMatrixStruct &sparsity)
{
  const unsigned int n_dofs = dof.n_dofs();

  Assert (dof_to_boundary_mapping.size() == n_dofs, ExcInternalError());
  Assert (boundary_indicators.find(255) == boundary_indicators.end(),
	  DoFHandler<dim>::ExcInvalidBoundaryIndicator());
  Assert (sparsity.n_rows() == dof.n_boundary_dofs(boundary_indicators),
	  ExcDimensionMismatch (sparsity.n_rows(), dof.n_boundary_dofs(boundary_indicators)));
  Assert (sparsity.n_cols() == dof.n_boundary_dofs(boundary_indicators),
	  ExcDimensionMismatch (sparsity.n_cols(), dof.n_boundary_dofs(boundary_indicators)));
  Assert (*max_element(dof_to_boundary_mapping.begin(),
		       dof_to_boundary_mapping.end()) == (signed int)sparsity.n_rows()-1,
	  ExcInternalError());

  const unsigned int dofs_per_face = dof.get_fe().dofs_per_face;
  vector<int> dofs_on_this_face(dofs_per_face);
  DoFHandler<dim>::active_face_iterator face = dof.begin_active_face(),
		       endf = dof.end_face();
  for (; face!=endf; ++face)
    if (boundary_indicators.find(face->boundary_indicator()) !=
	boundary_indicators.end())
      {
	face->get_dof_indices (dofs_on_this_face);

					 // make sure all dof indices have a
					 // boundary index
	Assert (*min_element(dofs_on_this_face.begin(),
			     dofs_on_this_face.end()) >=0,
		ExcInternalError());
					 // make sparsity pattern for this cell
	for (unsigned int i=0; i<dofs_per_face; ++i)
	  for (unsigned int j=0; j<dofs_per_face; ++j)
	    sparsity.add (dof_to_boundary_mapping[dofs_on_this_face[i]],
			  dof_to_boundary_mapping[dofs_on_this_face[j]]);
      };
};

#if deal_II_dimension == 1

//TODO: Implement make_flux_sparsity_pattern in 1D ?
template <>
void
DoFTools::make_flux_sparsity_pattern (const DoFHandler<1>&,
				      SparseMatrixStruct &)
{
  Assert(false, ExcNotImplemented());
}

#else

//TODO: Check this function for potential of optimization. (G)

template<int dim>
void
DoFTools::make_flux_sparsity_pattern (const DoFHandler<dim>& dof,
				      SparseMatrixStruct &sparsity)
{
  const unsigned int n_dofs = dof.n_dofs();

  Assert (sparsity.n_rows() == n_dofs,
	  ExcDimensionMismatch (sparsity.n_rows(), n_dofs));
  Assert (sparsity.n_cols() == n_dofs,
	  ExcDimensionMismatch (sparsity.n_cols(), n_dofs));

  const unsigned int total_dofs = dof.get_fe().dofs_per_cell;
  vector<int> dofs_on_this_cell(total_dofs);
  vector<int> dofs_on_other_cell(total_dofs);
  DoFHandler<dim>::active_cell_iterator cell = dof.begin_active(),
					endc = dof.end();
  for (; cell!=endc; ++cell)
    {
      cell->get_dof_indices (dofs_on_this_cell);
				       // make sparsity pattern for this cell
      for (unsigned int i=0; i<total_dofs; ++i)
	for (unsigned int j=0; j<total_dofs; ++j)
	  sparsity.add (dofs_on_this_cell[i],
			dofs_on_this_cell[j]);

				       // Loop over all interior neighbors
      for (unsigned int face = 0;
	   face < GeometryInfo<dim>::faces_per_cell;
	   ++face)
	{
	  if (! cell->at_boundary(face) )
	    {
	      DoFHandler<dim>::active_cell_iterator neighbor = cell->neighbor(face);
	      neighbor->get_dof_indices (dofs_on_other_cell);
					       // only add one direction
					       // The other is taken care of
					       // by neighbor.
	      for (unsigned int i=0; i<total_dofs; ++i)
		{
		  for (unsigned int j=0; j<total_dofs; ++j)
		    {
		      sparsity.add (dofs_on_this_cell[i],
				    dofs_on_other_cell[j]);
		    }
		}
	    }
	}
    }
}

#endif

template<int dim>
void
DoFTools::extract_dofs(const DoFHandler<dim> &dof,
		       const vector<bool>    &local_select,
		       vector<bool>          &selected_dofs)
{
  const FiniteElement<dim> &fe = dof.get_fe();
  Assert(local_select.size() == fe.n_components(),
	 ExcDimensionMismatch(local_select.size(), fe.n_components()));
  Assert(selected_dofs.size() == dof.n_dofs(),
	 ExcDimensionMismatch(selected_dofs.size(), dof.n_dofs()));

				   // preset all values by false
  fill_n (selected_dofs.begin(), dof.n_dofs(), false);

  vector<int> indices(fe.dofs_per_cell);

  DoFHandler<dim>::active_cell_iterator c;
  for (c = dof.begin_active() ; c != dof.end() ; ++ c)
    {
      c->get_dof_indices(indices);
      for (unsigned int i=0;i<fe.dofs_per_cell;++i)
	{
	  const unsigned int component = fe.system_to_component_index(i).first;

	  if (local_select[component] == true)
	    selected_dofs[indices[i]] = true;
	}
    }
}

template<int dim>
void
DoFTools::extract_level_dofs(const unsigned int       level,
			     const MGDoFHandler<dim> &dof,
			     const vector<bool>      &local_select,
			     vector<bool>            &selected_dofs)
{
  const FiniteElement<dim>& fe = dof.get_fe();
  Assert(local_select.size() == fe.n_components(),
	 ExcDimensionMismatch(local_select.size(), fe.n_components()));
  Assert(selected_dofs.size() == dof.n_dofs(level),
	 ExcDimensionMismatch(selected_dofs.size(), dof.n_dofs(level)));

				   // preset all values by false
  fill_n (selected_dofs.begin(), dof.n_dofs(level), false);

  vector<int> indices(fe.dofs_per_cell);

  MGDoFHandler<dim>::cell_iterator c;
  for (c = dof.begin(level) ; c != dof.end(level) ; ++ c)
    {
      c->get_mg_dof_indices(indices);
      for (unsigned int i=0;i<fe.dofs_per_cell;++i)
	{
	  const unsigned int component = fe.system_to_component_index(i).first;
	  if (local_select[component]  == true)
	    selected_dofs[indices[i]] = true;
	}
    }
}

// explicit instantiations
#if deal_II_dimension > 1
template void
DoFTools::make_flux_sparsity_pattern (const DoFHandler<deal_II_dimension>& dof,
				      SparseMatrixStruct &sparsity);
template void
DoFTools::make_boundary_sparsity_pattern (const DoFHandler<deal_II_dimension>& dof,
					  const vector<int>  &,
					  SparseMatrixStruct &);
template void
DoFTools::make_boundary_sparsity_pattern (const DoFHandler<deal_II_dimension>& dof,
					  const DoFHandler<deal_II_dimension>::FunctionMap  &boundary_indicators,
					  const vector<int>  &dof_to_boundary_mapping,
					  SparseMatrixStruct &sparsity);
#endif

template void
DoFTools::make_sparsity_pattern (const DoFHandler<deal_II_dimension>& dof,
					       SparseMatrixStruct &sparsity);

template void
DoFTools::make_sparsity_pattern (const DoFHandler<deal_II_dimension>& dof,
				 const vector<vector<bool> > &mask,
				 SparseMatrixStruct          &sparsity);

template void DoFTools::extract_dofs(const DoFHandler<deal_II_dimension>& dof,
				     const vector<bool>& local_select,
				     vector<bool>& selected_dofs);
template void DoFTools::extract_level_dofs(unsigned int level,
					   const MGDoFHandler<deal_II_dimension>& dof,
					   const vector<bool>& local_select,
					   vector<bool>& selected_dofs);

<commit_msg>Make function dimension independent.<commit_after>// $Id$
// Copyright Guido Kanschat, 1999

#include <grid/dof.h>
#include <grid/mg_dof.h>
#include <grid/dof_accessor.h>
#include <grid/mg_dof_accessor.h>
#include <grid/tria_iterator.h>
#include <fe/fe.h>
#include <fe/fe_system.h>
#include <basic/dof_tools.h>
#include <lac/sparsematrix.h>

#include <algorithm>

template <int dim>
void
DoFTools::make_sparsity_pattern (const DoFHandler<dim>& dof,
				 SparseMatrixStruct &sparsity)
{
  const unsigned int n_dofs = dof.n_dofs();

  Assert (sparsity.n_rows() == n_dofs,
	  ExcDimensionMismatch (sparsity.n_rows(), n_dofs));
  Assert (sparsity.n_cols() == n_dofs,
	  ExcDimensionMismatch (sparsity.n_cols(), n_dofs));

  const unsigned int dofs_per_cell = dof.get_fe().dofs_per_cell;
  vector<int> dofs_on_this_cell(dofs_per_cell);
  DoFHandler<dim>::active_cell_iterator cell = dof.begin_active(),
		       endc = dof.end();
  for (; cell!=endc; ++cell)
    {
      cell->get_dof_indices (dofs_on_this_cell);
				       // make sparsity pattern for this cell
      for (unsigned int i=0; i<dofs_per_cell; ++i)
	for (unsigned int j=0; j<dofs_per_cell; ++j)
	  sparsity.add (dofs_on_this_cell[i],
			dofs_on_this_cell[j]);
    }
}

template <int dim>
void
DoFTools::make_sparsity_pattern (const DoFHandler<dim>& dof,
					const vector<vector<bool> > &mask,
					SparseMatrixStruct          &sparsity)
{
  const unsigned int n_dofs = dof.n_dofs();
  const unsigned int dofs_per_cell = dof.get_fe().dofs_per_cell;

  Assert (sparsity.n_rows() == n_dofs,
	  ExcDimensionMismatch (sparsity.n_rows(), n_dofs));
  Assert (sparsity.n_cols() == n_dofs,
	  ExcDimensionMismatch (sparsity.n_cols(), n_dofs));
  Assert (mask.size() == dof.get_fe().n_components(),
	  ExcDimensionMismatch(mask.size(), dof.get_fe().n_components()));
  for (unsigned int i=0; i<mask.size(); ++i)
    Assert (mask[i].size() == dof.get_fe().n_components(),
	    ExcDimensionMismatch(mask[i].size(), dof.get_fe().n_components()));

				   // first build a mask for each dof,
				   // not like the one given which represents
				   // components
  vector<vector<bool> > dof_mask(dofs_per_cell,
				 vector<bool>(dofs_per_cell, false));
  for (unsigned int i=0; i<dofs_per_cell; ++i)
    for (unsigned int j=0; j<dofs_per_cell; ++j)
      dof_mask[i][j] = mask
		       [dof.get_fe().system_to_component_index(i).first]
		       [dof.get_fe().system_to_component_index(j).first];

  vector<int> dofs_on_this_cell(dofs_per_cell);
  DoFHandler<dim>::active_cell_iterator cell = dof.begin_active(),
		       endc = dof.end();
  for (; cell!=endc; ++cell)
    {
      cell->get_dof_indices (dofs_on_this_cell);
				       // make sparsity pattern for this cell
      for (unsigned int i=0; i<dofs_per_cell; ++i)
	for (unsigned int j=0; j<dofs_per_cell; ++j)
	  if (dof_mask[i][j] == true)
	    sparsity.add (dofs_on_this_cell[i],
			  dofs_on_this_cell[j]);
    }
}

#if deal_II_dimension == 1

template <>
void DoFTools::make_boundary_sparsity_pattern (const DoFHandler<1>&,
						    const vector<int>  &,
						    SparseMatrixStruct &)
{
    Assert (false, ExcInternalError());
};

template <>
void
DoFTools::make_boundary_sparsity_pattern (const DoFHandler<1>&,
					  const DoFHandler<1>::FunctionMap  &,
					  const vector<int>  &,
					  SparseMatrixStruct &)
{
  Assert (false, ExcInternalError());
}

#endif

template <int dim>
void
DoFTools::make_boundary_sparsity_pattern (const DoFHandler<dim>& dof,
					  const vector<int>  &dof_to_boundary_mapping,
					  SparseMatrixStruct &sparsity)
{
  const unsigned int n_dofs = dof.n_dofs();

  Assert (dof_to_boundary_mapping.size() == n_dofs, ExcInternalError());
  Assert (sparsity.n_rows() == dof.n_boundary_dofs(),
	  ExcDimensionMismatch (sparsity.n_rows(), dof.n_boundary_dofs()));
  Assert (sparsity.n_cols() == dof.n_boundary_dofs(),
	  ExcDimensionMismatch (sparsity.n_cols(), dof.n_boundary_dofs()));
  Assert (*max_element(dof_to_boundary_mapping.begin(),
		       dof_to_boundary_mapping.end()) == (signed int)sparsity.n_rows()-1,
	  ExcInternalError());

  const unsigned int dofs_per_face = dof.get_fe().dofs_per_face;
  vector<int> dofs_on_this_face(dofs_per_face);
  DoFHandler<dim>::active_face_iterator face = dof.begin_active_face(),
		       endf = dof.end_face();
  for (; face!=endf; ++face)
    if (face->at_boundary())
      {
	face->get_dof_indices (dofs_on_this_face);

					 // make sure all dof indices have a
					 // boundary index
	Assert (*min_element(dofs_on_this_face.begin(),
			     dofs_on_this_face.end()) >=0,
		ExcInternalError());

					 // make sparsity pattern for this cell
	for (unsigned int i=0; i<dofs_per_face; ++i)
	  for (unsigned int j=0; j<dofs_per_face; ++j)
	    sparsity.add (dof_to_boundary_mapping[dofs_on_this_face[i]],
			  dof_to_boundary_mapping[dofs_on_this_face[j]]);
      };
};

template <int dim>
void DoFTools::make_boundary_sparsity_pattern (const DoFHandler<dim>& dof,
					       const DoFHandler<dim>::FunctionMap  &boundary_indicators,
					       const vector<int>  &dof_to_boundary_mapping,
					       SparseMatrixStruct &sparsity)
{
  const unsigned int n_dofs = dof.n_dofs();

  Assert (dof_to_boundary_mapping.size() == n_dofs, ExcInternalError());
  Assert (boundary_indicators.find(255) == boundary_indicators.end(),
	  DoFHandler<dim>::ExcInvalidBoundaryIndicator());
  Assert (sparsity.n_rows() == dof.n_boundary_dofs(boundary_indicators),
	  ExcDimensionMismatch (sparsity.n_rows(), dof.n_boundary_dofs(boundary_indicators)));
  Assert (sparsity.n_cols() == dof.n_boundary_dofs(boundary_indicators),
	  ExcDimensionMismatch (sparsity.n_cols(), dof.n_boundary_dofs(boundary_indicators)));
  Assert (*max_element(dof_to_boundary_mapping.begin(),
		       dof_to_boundary_mapping.end()) == (signed int)sparsity.n_rows()-1,
	  ExcInternalError());

  const unsigned int dofs_per_face = dof.get_fe().dofs_per_face;
  vector<int> dofs_on_this_face(dofs_per_face);
  DoFHandler<dim>::active_face_iterator face = dof.begin_active_face(),
		       endf = dof.end_face();
  for (; face!=endf; ++face)
    if (boundary_indicators.find(face->boundary_indicator()) !=
	boundary_indicators.end())
      {
	face->get_dof_indices (dofs_on_this_face);

					 // make sure all dof indices have a
					 // boundary index
	Assert (*min_element(dofs_on_this_face.begin(),
			     dofs_on_this_face.end()) >=0,
		ExcInternalError());
					 // make sparsity pattern for this cell
	for (unsigned int i=0; i<dofs_per_face; ++i)
	  for (unsigned int j=0; j<dofs_per_face; ++j)
	    sparsity.add (dof_to_boundary_mapping[dofs_on_this_face[i]],
			  dof_to_boundary_mapping[dofs_on_this_face[j]]);
      };
};

//TODO: Check this function for potential of optimization. (G)

template<int dim>
void
DoFTools::make_flux_sparsity_pattern (const DoFHandler<dim>& dof,
				      SparseMatrixStruct &sparsity)
{
  const unsigned int n_dofs = dof.n_dofs();

  Assert (sparsity.n_rows() == n_dofs,
	  ExcDimensionMismatch (sparsity.n_rows(), n_dofs));
  Assert (sparsity.n_cols() == n_dofs,
	  ExcDimensionMismatch (sparsity.n_cols(), n_dofs));

  const unsigned int total_dofs = dof.get_fe().dofs_per_cell;
  vector<int> dofs_on_this_cell(total_dofs);
  vector<int> dofs_on_other_cell(total_dofs);
  DoFHandler<dim>::active_cell_iterator cell = dof.begin_active(),
					endc = dof.end();
  for (; cell!=endc; ++cell)
    {
      cell->get_dof_indices (dofs_on_this_cell);
				       // make sparsity pattern for this cell
      for (unsigned int i=0; i<total_dofs; ++i)
	for (unsigned int j=0; j<total_dofs; ++j)
	  sparsity.add (dofs_on_this_cell[i],
			dofs_on_this_cell[j]);

				       // Loop over all interior neighbors
      for (unsigned int face = 0;
	   face < GeometryInfo<dim>::faces_per_cell;
	   ++face)
	{
	  if (! cell->at_boundary(face) )
	    {
	      DoFHandler<dim>::active_cell_iterator neighbor = cell->neighbor(face);
	      neighbor->get_dof_indices (dofs_on_other_cell);
					       // only add one direction
					       // The other is taken care of
					       // by neighbor.
	      for (unsigned int i=0; i<total_dofs; ++i)
		{
		  for (unsigned int j=0; j<total_dofs; ++j)
		    {
		      sparsity.add (dofs_on_this_cell[i],
				    dofs_on_other_cell[j]);
		    }
		}
	    }
	}
    }
}

template<int dim>
void
DoFTools::extract_dofs(const DoFHandler<dim> &dof,
		       const vector<bool>    &local_select,
		       vector<bool>          &selected_dofs)
{
  const FiniteElement<dim> &fe = dof.get_fe();
  Assert(local_select.size() == fe.n_components(),
	 ExcDimensionMismatch(local_select.size(), fe.n_components()));
  Assert(selected_dofs.size() == dof.n_dofs(),
	 ExcDimensionMismatch(selected_dofs.size(), dof.n_dofs()));

				   // preset all values by false
  fill_n (selected_dofs.begin(), dof.n_dofs(), false);

  vector<int> indices(fe.dofs_per_cell);

  DoFHandler<dim>::active_cell_iterator c;
  for (c = dof.begin_active() ; c != dof.end() ; ++ c)
    {
      c->get_dof_indices(indices);
      for (unsigned int i=0;i<fe.dofs_per_cell;++i)
	{
	  const unsigned int component = fe.system_to_component_index(i).first;

	  if (local_select[component] == true)
	    selected_dofs[indices[i]] = true;
	}
    }
}

template<int dim>
void
DoFTools::extract_level_dofs(const unsigned int       level,
			     const MGDoFHandler<dim> &dof,
			     const vector<bool>      &local_select,
			     vector<bool>            &selected_dofs)
{
  const FiniteElement<dim>& fe = dof.get_fe();
  Assert(local_select.size() == fe.n_components(),
	 ExcDimensionMismatch(local_select.size(), fe.n_components()));
  Assert(selected_dofs.size() == dof.n_dofs(level),
	 ExcDimensionMismatch(selected_dofs.size(), dof.n_dofs(level)));

				   // preset all values by false
  fill_n (selected_dofs.begin(), dof.n_dofs(level), false);

  vector<int> indices(fe.dofs_per_cell);

  MGDoFHandler<dim>::cell_iterator c;
  for (c = dof.begin(level) ; c != dof.end(level) ; ++ c)
    {
      c->get_mg_dof_indices(indices);
      for (unsigned int i=0;i<fe.dofs_per_cell;++i)
	{
	  const unsigned int component = fe.system_to_component_index(i).first;
	  if (local_select[component]  == true)
	    selected_dofs[indices[i]] = true;
	}
    }
}

// explicit instantiations
#if deal_II_dimension > 1
template void
DoFTools::make_flux_sparsity_pattern (const DoFHandler<deal_II_dimension>& dof,
				      SparseMatrixStruct &sparsity);
template void
DoFTools::make_boundary_sparsity_pattern (const DoFHandler<deal_II_dimension>& dof,
					  const vector<int>  &,
					  SparseMatrixStruct &);
template void
DoFTools::make_boundary_sparsity_pattern (const DoFHandler<deal_II_dimension>& dof,
					  const DoFHandler<deal_II_dimension>::FunctionMap  &boundary_indicators,
					  const vector<int>  &dof_to_boundary_mapping,
					  SparseMatrixStruct &sparsity);
#endif

template void
DoFTools::make_sparsity_pattern (const DoFHandler<deal_II_dimension>& dof,
					       SparseMatrixStruct &sparsity);

template void
DoFTools::make_sparsity_pattern (const DoFHandler<deal_II_dimension>& dof,
				 const vector<vector<bool> > &mask,
				 SparseMatrixStruct          &sparsity);

template void DoFTools::extract_dofs(const DoFHandler<deal_II_dimension>& dof,
				     const vector<bool>& local_select,
				     vector<bool>& selected_dofs);
template void DoFTools::extract_level_dofs(unsigned int level,
					   const MGDoFHandler<deal_II_dimension>& dof,
					   const vector<bool>& local_select,
					   vector<bool>& selected_dofs);

<|endoftext|>


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

#include <cassert>
#include <cstddef>
#include <fstream>
#include <map>
#include <string>

#include "configreader.h"
#include "jit.h"
#include "jump-x86.h"
#include "plugin.h"
#include "version.h"

#ifdef WIN32
	#include <Windows.h>
#else
	#ifndef _GNU_SOURCE
		#define _GNU_SOURCE 1 // for dladdr()
	#endif
	#include <dlfcn.h>
#endif

extern void *pAMXFunctions;

typedef void (*logprintf_t)(const char *format, ...);
static logprintf_t logprintf;

typedef std::map<AMX*, jit::Jitter*> AmxToJitterMap;
static AmxToJitterMap amx_to_jitter;

static JumpX86 amx_Exec_hook;
static JumpX86 amx_GetAddr_hook;

static cell *opcode_list = 0;

static ConfigReader server_cfg("server.cfg");

static int AMXAPI amx_GetAddr_JIT(AMX *amx, cell amx_addr, cell **phys_addr) {
	AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);
	*phys_addr = reinterpret_cast<cell*>(amx->base + hdr->dat + amx_addr);
	return AMX_ERR_NONE;
}

static int AMXAPI amx_Exec_JIT(AMX *amx, cell *retval, int index) {
	// A Jitter instance associated with this AMX.
	jit::Jitter *jitter = 0;

	// When amx_Exec() is called for the first time attempt to
	// JIT-compile this AMX. In case of compilation failure a null
	// pointer is put into amx_to_jit map to indicate this.
	AmxToJitterMap::iterator iterator = amx_to_jitter.find(amx);
	if (iterator == amx_to_jitter.end()) {
		jitter = new jit::Jitter(amx, ::opcode_list);
		int error = AMX_ERR_NONE;
		try {
			jitter->Compile();
		} catch (const jit::JitError &) {
			try {
				logprintf("[jit] An error occured, this script will run without JIT!");
				throw;
			} catch (const jit::CompileError &e) {
				const jit::AmxInstruction &instr = e.GetInstruction();
				AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);
				cell address = reinterpret_cast<cell>(instr.GetIP())
							 - reinterpret_cast<cell>(amx->base + hdr->cod);
				try {
					throw;
				} catch (const jit::InvalidInstructionError &) {
					logprintf("[jit] Error: Invalid instruction at address %08x:", address);
				} catch (const jit::UnsupportedInstructionError &) {
					logprintf("[jit] Error: Unsupported instruction at address %08x:", address);
				} catch (const jit::ObsoleteInstructionError &) {
					logprintf("[jit] Error: Obsolete instruction at address %08x:", address);
				}
				const cell *ip = instr.GetIP();
				logprintf("  %08x %08x %08x %08x %08x %08x ...",
						*ip, *(ip + 1), *(ip + 2), *(ip + 3), *(ip + 4), *(ip + 5));
				error = AMX_ERR_INVINSTR;
			}
		}
		if (error != AMX_ERR_NONE) {
			delete jitter;
			jitter = 0;
		}
		amx_to_jitter.insert(std::make_pair(amx, jitter));
	} else {
		jitter = iterator->second;
	}

	if (jitter == 0) {
		// Compilation previously failed, call normal amx_Exec().
		JumpX86::ScopedRemove r(&amx_Exec_hook);
		return amx_Exec(amx, retval, index);
	} else {
		return jitter->CallPublicFunction(index, retval);
	}
}

static std::string GetModuleNameBySymbol(void *symbol) {
	char module[FILENAME_MAX] = "";
	if (symbol != 0) {
		#ifdef WIN32
			MEMORY_BASIC_INFORMATION mbi;
			VirtualQuery(symbol, &mbi, sizeof(mbi));
			GetModuleFileName((HMODULE)mbi.AllocationBase, module, FILENAME_MAX);
		#else
			Dl_info info;
			dladdr(symbol, &info);
			strcpy(module, info.dli_fname);
		#endif
	}
	return std::string(module);
}

static std::string GetFileName(const std::string &path) {
	std::string::size_type lastSep = path.find_last_of("/\\");
	if (lastSep != std::string::npos) {
		return path.substr(lastSep + 1);
	}
	return path;
}

PLUGIN_EXPORT unsigned int PLUGIN_CALL Supports() {
	return SUPPORTS_VERSION | SUPPORTS_AMX_NATIVES;
}

PLUGIN_EXPORT bool PLUGIN_CALL Load(void **ppData) {
	logprintf = (logprintf_t)ppData[PLUGIN_DATA_LOGPRINTF];
	pAMXFunctions = reinterpret_cast<void*>(ppData[PLUGIN_DATA_AMX_EXPORTS]);

	void *funAddr = JumpX86::GetTargetAddress(((void**)pAMXFunctions)[PLUGIN_AMX_EXPORT_Exec]);
	if (funAddr != 0) {
		std::string module = GetFileName(GetModuleNameBySymbol(funAddr));
		if (!module.empty() && module != "samp-server.exe" && module != "samp03svr") {
			logprintf("  JIT must be loaded before %s", module.c_str());
			return false;
		}
	}

	std::size_t stack_size = server_cfg.GetOption("jit_stack", 0);
	if (stack_size != 0) {
		jit::Jitter::SetStackSize(stack_size);
	}

	logprintf("  JIT plugin v%s is OK.", PLUGIN_VERSION_STRING);
	return true;
}

PLUGIN_EXPORT void PLUGIN_CALL Unload() {
	for (AmxToJitterMap::iterator it = amx_to_jitter.begin();
			it != amx_to_jitter.end(); ++it) {
		delete it->second;
	}
}

PLUGIN_EXPORT int PLUGIN_CALL AmxLoad(AMX *amx) {
	typedef int (AMXAPI *amx_Exec_t)(AMX *amx, cell *retval, int index);
	amx_Exec_t amx_Exec = (amx_Exec_t)((void**)pAMXFunctions)[PLUGIN_AMX_EXPORT_Exec];

	typedef int (AMXAPI *amx_GetAddr_t)(AMX *amx, cell amx_addr, cell **phys_addr);
	amx_GetAddr_t amx_GetAddr = (amx_GetAddr_t)((void**)pAMXFunctions)[PLUGIN_AMX_EXPORT_GetAddr];

	#if defined __GNUC__ && !defined WIN32
		// Get opcode list before we hook amx_Exec().
		if (::opcode_list == 0) {
			amx->flags |= AMX_FLAG_BROWSE;
			amx_Exec(amx, reinterpret_cast<cell*>(&opcode_list), 0);
			amx->flags &= ~AMX_FLAG_BROWSE;
		}
	#endif

	if (!amx_Exec_hook.IsInstalled()) {
		amx_Exec_hook.Install(
			(void*)amx_Exec,
			(void*)amx_Exec_JIT);
	}
	if (!amx_GetAddr_hook.IsInstalled()) {
		amx_GetAddr_hook.Install(
			(void*)amx_GetAddr,
			(void*)amx_GetAddr_JIT);
	}

	return AMX_ERR_NONE;
}

PLUGIN_EXPORT int PLUGIN_CALL AmxUnload(AMX *amx) {
	AmxToJitterMap::iterator it = amx_to_jitter.find(amx);
	if (it != amx_to_jitter.end()) {
		delete it->second;
		amx_to_jitter.erase(it);
	}
	return AMX_ERR_NONE;
}
<commit_msg>Revert "Remove amx_BrowseRelocate() support code from amx_Exec_JIT()"<commit_after>// Copyright (c) 2012, Zeex
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <cassert>
#include <cstddef>
#include <fstream>
#include <map>
#include <string>

#include "configreader.h"
#include "jit.h"
#include "jump-x86.h"
#include "plugin.h"
#include "version.h"

#ifdef WIN32
	#include <Windows.h>
#else
	#ifndef _GNU_SOURCE
		#define _GNU_SOURCE 1 // for dladdr()
	#endif
	#include <dlfcn.h>
#endif

extern void *pAMXFunctions;

typedef void (*logprintf_t)(const char *format, ...);
static logprintf_t logprintf;

typedef std::map<AMX*, jit::Jitter*> AmxToJitterMap;
static AmxToJitterMap amx_to_jitter;

static JumpX86 amx_Exec_hook;
static JumpX86 amx_GetAddr_hook;

static cell *opcode_list = 0;

static ConfigReader server_cfg("server.cfg");

static int AMXAPI amx_GetAddr_JIT(AMX *amx, cell amx_addr, cell **phys_addr) {
	AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);
	*phys_addr = reinterpret_cast<cell*>(amx->base + hdr->dat + amx_addr);
	return AMX_ERR_NONE;
}

static int AMXAPI amx_Exec_JIT(AMX *amx, cell *retval, int index) {
	#if defined __GNUC__ && !defined WIN32
		if ((amx->flags & AMX_FLAG_BROWSE) == AMX_FLAG_BROWSE) {
			// amx_BrowseRelocate() wants the opcode list.
			assert(::opcode_list != 0);
			*retval = reinterpret_cast<cell>(::opcode_list);
			return AMX_ERR_NONE;
		}
	#endif

	// A Jitter instance associated with this AMX.
	jit::Jitter *jitter = 0;

	// When amx_Exec() is called for the first time attempt to
	// JIT-compile this AMX. In case of compilation failure a null
	// pointer is put into amx_to_jit map to indicate this.
	AmxToJitterMap::iterator iterator = amx_to_jitter.find(amx);
	if (iterator == amx_to_jitter.end()) {
		jitter = new jit::Jitter(amx, ::opcode_list);
		int error = AMX_ERR_NONE;
		try {
			jitter->Compile();
		} catch (const jit::JitError &) {
			try {
				logprintf("[jit] An error occured, this script will run without JIT!");
				throw;
			} catch (const jit::CompileError &e) {
				const jit::AmxInstruction &instr = e.GetInstruction();
				AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);
				cell address = reinterpret_cast<cell>(instr.GetIP())
							 - reinterpret_cast<cell>(amx->base + hdr->cod);
				try {
					throw;
				} catch (const jit::InvalidInstructionError &) {
					logprintf("[jit] Error: Invalid instruction at address %08x:", address);
				} catch (const jit::UnsupportedInstructionError &) {
					logprintf("[jit] Error: Unsupported instruction at address %08x:", address);
				} catch (const jit::ObsoleteInstructionError &) {
					logprintf("[jit] Error: Obsolete instruction at address %08x:", address);
				}
				const cell *ip = instr.GetIP();
				logprintf("  %08x %08x %08x %08x %08x %08x ...",
						*ip, *(ip + 1), *(ip + 2), *(ip + 3), *(ip + 4), *(ip + 5));
				error = AMX_ERR_INVINSTR;
			}
		}
		if (error != AMX_ERR_NONE) {
			delete jitter;
			jitter = 0;
		}
		amx_to_jitter.insert(std::make_pair(amx, jitter));
	} else {
		jitter = iterator->second;
	}

	if (jitter == 0) {
		// Compilation previously failed, call normal amx_Exec().
		JumpX86::ScopedRemove r(&amx_Exec_hook);
		return amx_Exec(amx, retval, index);
	} else {
		return jitter->CallPublicFunction(index, retval);
	}
}

static std::string GetModuleNameBySymbol(void *symbol) {
	char module[FILENAME_MAX] = "";
	if (symbol != 0) {
		#ifdef WIN32
			MEMORY_BASIC_INFORMATION mbi;
			VirtualQuery(symbol, &mbi, sizeof(mbi));
			GetModuleFileName((HMODULE)mbi.AllocationBase, module, FILENAME_MAX);
		#else
			Dl_info info;
			dladdr(symbol, &info);
			strcpy(module, info.dli_fname);
		#endif
	}
	return std::string(module);
}

static std::string GetFileName(const std::string &path) {
	std::string::size_type lastSep = path.find_last_of("/\\");
	if (lastSep != std::string::npos) {
		return path.substr(lastSep + 1);
	}
	return path;
}

PLUGIN_EXPORT unsigned int PLUGIN_CALL Supports() {
	return SUPPORTS_VERSION | SUPPORTS_AMX_NATIVES;
}

PLUGIN_EXPORT bool PLUGIN_CALL Load(void **ppData) {
	logprintf = (logprintf_t)ppData[PLUGIN_DATA_LOGPRINTF];
	pAMXFunctions = reinterpret_cast<void*>(ppData[PLUGIN_DATA_AMX_EXPORTS]);

	void *funAddr = JumpX86::GetTargetAddress(((void**)pAMXFunctions)[PLUGIN_AMX_EXPORT_Exec]);
	if (funAddr != 0) {
		std::string module = GetFileName(GetModuleNameBySymbol(funAddr));
		if (!module.empty() && module != "samp-server.exe" && module != "samp03svr") {
			logprintf("  JIT must be loaded before %s", module.c_str());
			return false;
		}
	}

	std::size_t stack_size = server_cfg.GetOption("jit_stack", 0);
	if (stack_size != 0) {
		jit::Jitter::SetStackSize(stack_size);
	}

	logprintf("  JIT plugin v%s is OK.", PLUGIN_VERSION_STRING);
	return true;
}

PLUGIN_EXPORT void PLUGIN_CALL Unload() {
	for (AmxToJitterMap::iterator it = amx_to_jitter.begin();
			it != amx_to_jitter.end(); ++it) {
		delete it->second;
	}
}

PLUGIN_EXPORT int PLUGIN_CALL AmxLoad(AMX *amx) {
	typedef int (AMXAPI *amx_Exec_t)(AMX *amx, cell *retval, int index);
	amx_Exec_t amx_Exec = (amx_Exec_t)((void**)pAMXFunctions)[PLUGIN_AMX_EXPORT_Exec];

	typedef int (AMXAPI *amx_GetAddr_t)(AMX *amx, cell amx_addr, cell **phys_addr);
	amx_GetAddr_t amx_GetAddr = (amx_GetAddr_t)((void**)pAMXFunctions)[PLUGIN_AMX_EXPORT_GetAddr];

	#if defined __GNUC__ && !defined WIN32
		// Get opcode list before we hook amx_Exec().
		if (::opcode_list == 0) {
			amx->flags |= AMX_FLAG_BROWSE;
			amx_Exec(amx, reinterpret_cast<cell*>(&opcode_list), 0);
			amx->flags &= ~AMX_FLAG_BROWSE;
		}
	#endif

	if (!amx_Exec_hook.IsInstalled()) {
		amx_Exec_hook.Install(
			(void*)amx_Exec,
			(void*)amx_Exec_JIT);
	}
	if (!amx_GetAddr_hook.IsInstalled()) {
		amx_GetAddr_hook.Install(
			(void*)amx_GetAddr,
			(void*)amx_GetAddr_JIT);
	}

	return AMX_ERR_NONE;
}

PLUGIN_EXPORT int PLUGIN_CALL AmxUnload(AMX *amx) {
	AmxToJitterMap::iterator it = amx_to_jitter.find(amx);
	if (it != amx_to_jitter.end()) {
		delete it->second;
		amx_to_jitter.erase(it);
	}
	return AMX_ERR_NONE;
}
<|endoftext|>


<commit_before>// The libMesh Finite Element Library.
// Copyright (C) 2002-2018 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// 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.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// C++ includes
#include <fstream>

// Local includes
#include "libmesh/libmesh_config.h"
#include "libmesh/ucd_io.h"
#include "libmesh/mesh_base.h"
#include "libmesh/face_quad4.h"
#include "libmesh/face_tri3.h"
#include "libmesh/cell_tet4.h"
#include "libmesh/cell_hex8.h"
#include "libmesh/cell_prism6.h"
#include "libmesh/enum_io_package.h"
#include "libmesh/enum_elem_type.h"

#ifdef LIBMESH_HAVE_GZSTREAM
# include "libmesh/ignore_warnings.h" // shadowing in gzstream.h
# include "gzstream.h" // For reading/writing compressed streams
# include "libmesh/restore_warnings.h"
#endif

namespace libMesh
{

// Initialize the static data members by calling the static build functions.
std::map<ElemType, std::string> UCDIO::_writing_element_map = UCDIO::build_writing_element_map();
std::map<std::string, ElemType> UCDIO::_reading_element_map = UCDIO::build_reading_element_map();

// Static function used to build the _writing_element_map.
std::map<ElemType, std::string> UCDIO::build_writing_element_map()
{
  std::map<ElemType, std::string> ret;
  ret[EDGE2]    = "edge";
  ret[TRI3]     = "tri";
  ret[QUAD4]    = "quad";
  ret[TET4]     = "tet";
  ret[HEX8]     = "hex";
  ret[PRISM6]   = "prism";
  ret[PYRAMID5] = "pyramid";
  return ret;
}

// Static function used to build the _reading_element_map.
std::map<std::string, ElemType> UCDIO::build_reading_element_map()
{
  std::map<std::string, ElemType> ret;
  ret["edge"]    = EDGE2;
  ret["tri"]     = TRI3;
  ret["quad"]    = QUAD4;
  ret["tet"]     = TET4;
  ret["hex"]     = HEX8;
  ret["prism"]   = PRISM6;
  ret["pyramid"] = PYRAMID5;
  return ret;
}

void UCDIO::read (const std::string & file_name)
{
  if (file_name.rfind(".gz") < file_name.size())
    {
#ifdef LIBMESH_HAVE_GZSTREAM
      igzstream in_stream (file_name.c_str());
      this->read_implementation (in_stream);
#else
      libmesh_error_msg("ERROR:  You must have the zlib.h header files and libraries to read and write compressed streams.");
#endif
    }

  else
    {
      std::ifstream in_stream (file_name.c_str());
      this->read_implementation (in_stream);
    }
}

void UCDIO::write (const std::string & file_name)
{
  if (file_name.rfind(".gz") < file_name.size())
    {
#ifdef LIBMESH_HAVE_GZSTREAM
      ogzstream out_stream (file_name.c_str());
      this->write_implementation (out_stream);
#else
      libmesh_error_msg("ERROR:  You must have the zlib.h header files and libraries to read and write compressed streams.");
#endif
    }

  else
    {
      std::ofstream out_stream (file_name.c_str());
      this->write_implementation (out_stream);
    }
}

void UCDIO::read_implementation (std::istream & in)
{
  // This is a serial-only process for now;
  // the Mesh should be read on processor 0 and
  // broadcast later
  libmesh_assert_equal_to (MeshOutput<MeshBase>::mesh().processor_id(), 0);

  // Check input buffer
  libmesh_assert (in.good());

  MeshBase & mesh = MeshInput<MeshBase>::mesh();

  // Keep track of what kinds of elements this file contains
  elems_of_dimension.clear();
  elems_of_dimension.resize(4, false);

  this->skip_comment_lines (in, '#');

  unsigned int nNodes=0, nElem=0, dummy=0;

  in >> nNodes   // Read the number of nodes from the stream
     >> nElem    // Read the number of elements from the stream
     >> dummy
     >> dummy
     >> dummy;

  // Read the nodal coordinates. Note that UCD format always
  // stores (x,y,z), and in 2D z=0. We don't need to store this,
  // however.  So, we read in x,y,z for each node and make a point
  // in the proper way based on what dimension we're in
  {
    Point xyz;

    for (unsigned int i=0; i<nNodes; i++)
      {
        libmesh_assert (in.good());

        in >> dummy   // Point number
           >> xyz(0)  // x-coordinate value
           >> xyz(1)  // y-coordinate value
           >> xyz(2); // z-coordinate value

        // Build the node
        mesh.add_point (xyz, i);
      }
  }

  // Read the elements from the stream. Notice that the UCD node-numbering
  // scheme is 1-based, and we just created a 0-based scheme above
  // (which is of course what we want). So, when we read in the nodal
  // connectivity for each element we need to take 1 off the value of
  // each node so that we get the right thing.
  {
    unsigned int material_id=0, node=0;
    std::string type;

    for (unsigned int i=0; i<nElem; i++)
      {
        libmesh_assert (in.good());

        // The cell type can be either tri, quad, tet, hex, or prism.
        in >> dummy        // Cell number, means nothing to us
           >> material_id  // We'll use this for the element subdomain id.
           >> type;        // string describing cell type

        // Convert the UCD type string to a libmesh ElementType
        auto it = _reading_element_map.find(type);
        if (it == _reading_element_map.end())
          libmesh_error_msg("Unsupported element type = " << type);

        // Build the required type and release it into our custody.
        Elem * elem = Elem::build(it->second).release();

        for (unsigned int n=0; n<elem->n_nodes(); n++)
          {
            libmesh_assert (in.good());

            in >> node; // read the current node
            node -= 1;  // UCD is 1-based, so subtract

            libmesh_assert_less (node, mesh.n_nodes());

            // assign the node
            elem->set_node(n) = mesh.node_ptr(node);
          }

        elems_of_dimension[elem->dim()] = true;

        // Set the element's subdomain ID based on the material_id.
        elem->subdomain_id() = cast_int<subdomain_id_type>(material_id);

        // Add the element to the mesh
        elem->set_id(i);
        mesh.add_elem (elem);
      }

    // Set the mesh dimension to the largest encountered for an element
    for (unsigned char i=0; i!=4; ++i)
      if (elems_of_dimension[i])
        mesh.set_mesh_dimension(i);

#if LIBMESH_DIM < 3
    if (mesh.mesh_dimension() > LIBMESH_DIM)
      libmesh_error_msg("Cannot open dimension " \
                        << mesh.mesh_dimension() \
                        << " mesh file when configured without " \
                        << mesh.mesh_dimension() \
                        << "D support.");
#endif
  }
}

void UCDIO::write_implementation (std::ostream & out_stream)
{
  libmesh_assert (out_stream.good());

  const MeshBase & mesh = MeshOutput<MeshBase>::mesh();

  // UCD doesn't work any dimension except 3?
  if (mesh.mesh_dimension() != 3)
    libmesh_error_msg("Error: Can't write boundary elements for meshes of dimension less than 3. " \
                      << "Mesh dimension = " << mesh.mesh_dimension());

  // Write header
  this->write_header(out_stream, mesh, mesh.n_elem(), 0);

  // Write the node coordinates
  this->write_nodes(out_stream, mesh);

  // Write the elements
  this->write_interior_elems(out_stream, mesh);
}

void UCDIO::write_header(std::ostream & out_stream,
                         const MeshBase & mesh,
                         dof_id_type n_elems,
                         unsigned int n_vars)
{
  libmesh_assert (out_stream.good());
  // TODO: We could print out the libmesh revision used to write this file here.
  out_stream << "# For a description of the UCD format see the AVS Developer's guide.\n"
             << "#\n";

  // Write the mesh info
  out_stream << mesh.n_nodes() << " "
             << n_elems  << " "
             << n_vars << " "
             << " 0 0\n";
}

void UCDIO::write_nodes(std::ostream & out_stream,
                        const MeshBase & mesh)
{
  // 1-based node number for UCD
  unsigned int n=1;

  // Write the node coordinates
  for (auto & node : mesh.node_ptr_range())
    {
      libmesh_assert (out_stream.good());

      out_stream << n++ << "\t";
      node->write_unformatted(out_stream);
    }
}

void UCDIO::write_interior_elems(std::ostream & out_stream,
                                 const MeshBase & mesh)
{
  // 1-based element number for UCD
  unsigned int e=1;

  // Write element information
  for (const auto & elem : mesh.element_ptr_range())
    {
      libmesh_assert (out_stream.good());

      // Look up the corresponding UCD element type in the static map.
      const ElemType etype = elem->type();
      auto it = _writing_element_map.find(etype);
      if (it == _writing_element_map.end())
        libmesh_error_msg("Error: Unsupported ElemType " << etype << " for UCDIO.");

      // Write the element's subdomain ID as the UCD "material_id".
      out_stream << e++ << " " << elem->subdomain_id() << " " << it->second << "\t";
      elem->write_connectivity(out_stream, UCD);
    }
}

void UCDIO::write_nodal_data(const std::string & fname,
                             const std::vector<Number> & soln,
                             const std::vector<std::string> & names)
{
  const MeshBase & mesh = MeshOutput<MeshBase>::mesh();

  const dof_id_type n_elem = mesh.n_elem();

  // Only processor 0 does the writing
  if (mesh.processor_id())
    return;

  std::ofstream out_stream(fname.c_str());

  // UCD doesn't work in 1D
  libmesh_assert (mesh.mesh_dimension() != 1);

  // Write header
  this->write_header(out_stream,mesh,n_elem,
                     cast_int<unsigned int>(names.size()));

  // Write the node coordinates
  this->write_nodes(out_stream, mesh);

  // Write the elements
  this->write_interior_elems(out_stream, mesh);

  // Write the solution
  this->write_soln(out_stream, mesh, names, soln);
}

void UCDIO::write_soln(std::ostream & out_stream,
                       const MeshBase & mesh,
                       const std::vector<std::string> & names,
                       const std::vector<Number> & soln)
{
  libmesh_assert (out_stream.good());

  // First write out how many variables and how many components per variable
  out_stream << names.size();
  for (std::size_t i = 0; i < names.size(); i++)
    {
      libmesh_assert (out_stream.good());
      // Each named variable has only 1 component
      out_stream << " 1";
    }
  out_stream << std::endl;

  // Now write out variable names and units. Since we don't store units
  // We just write out dummy.
  {
    std::vector<std::string>::const_iterator var = names.begin();
    for (; var != names.end(); ++var)
      {
        libmesh_assert (out_stream.good());
        out_stream << *var << ", dummy" << std::endl;
      }
  }

  // Now, for each node, write out the solution variables.
  // We use a 1-based node numbering for UCD.
  std::size_t nv = names.size();
  for (std::size_t n = 1; n <= mesh.n_nodes(); n++)
    {
      libmesh_assert (out_stream.good());
      out_stream << n;

      for (std::size_t var = 0; var != nv; var++)
        {
          std::size_t idx = nv*(n-1) + var;

          out_stream << " " << soln[idx];
        }
      out_stream << std::endl;
    }
}

} // namespace libMesh
<commit_msg>Remove iterator boilerplate in UCDIO.<commit_after>// The libMesh Finite Element Library.
// Copyright (C) 2002-2018 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// 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.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// C++ includes
#include <fstream>

// Local includes
#include "libmesh/libmesh_config.h"
#include "libmesh/ucd_io.h"
#include "libmesh/mesh_base.h"
#include "libmesh/face_quad4.h"
#include "libmesh/face_tri3.h"
#include "libmesh/cell_tet4.h"
#include "libmesh/cell_hex8.h"
#include "libmesh/cell_prism6.h"
#include "libmesh/enum_io_package.h"
#include "libmesh/enum_elem_type.h"

#ifdef LIBMESH_HAVE_GZSTREAM
# include "libmesh/ignore_warnings.h" // shadowing in gzstream.h
# include "gzstream.h" // For reading/writing compressed streams
# include "libmesh/restore_warnings.h"
#endif

namespace libMesh
{

// Initialize the static data members by calling the static build functions.
std::map<ElemType, std::string> UCDIO::_writing_element_map = UCDIO::build_writing_element_map();
std::map<std::string, ElemType> UCDIO::_reading_element_map = UCDIO::build_reading_element_map();

// Static function used to build the _writing_element_map.
std::map<ElemType, std::string> UCDIO::build_writing_element_map()
{
  std::map<ElemType, std::string> ret;
  ret[EDGE2]    = "edge";
  ret[TRI3]     = "tri";
  ret[QUAD4]    = "quad";
  ret[TET4]     = "tet";
  ret[HEX8]     = "hex";
  ret[PRISM6]   = "prism";
  ret[PYRAMID5] = "pyramid";
  return ret;
}

// Static function used to build the _reading_element_map.
std::map<std::string, ElemType> UCDIO::build_reading_element_map()
{
  std::map<std::string, ElemType> ret;
  ret["edge"]    = EDGE2;
  ret["tri"]     = TRI3;
  ret["quad"]    = QUAD4;
  ret["tet"]     = TET4;
  ret["hex"]     = HEX8;
  ret["prism"]   = PRISM6;
  ret["pyramid"] = PYRAMID5;
  return ret;
}

void UCDIO::read (const std::string & file_name)
{
  if (file_name.rfind(".gz") < file_name.size())
    {
#ifdef LIBMESH_HAVE_GZSTREAM
      igzstream in_stream (file_name.c_str());
      this->read_implementation (in_stream);
#else
      libmesh_error_msg("ERROR:  You must have the zlib.h header files and libraries to read and write compressed streams.");
#endif
    }

  else
    {
      std::ifstream in_stream (file_name.c_str());
      this->read_implementation (in_stream);
    }
}

void UCDIO::write (const std::string & file_name)
{
  if (file_name.rfind(".gz") < file_name.size())
    {
#ifdef LIBMESH_HAVE_GZSTREAM
      ogzstream out_stream (file_name.c_str());
      this->write_implementation (out_stream);
#else
      libmesh_error_msg("ERROR:  You must have the zlib.h header files and libraries to read and write compressed streams.");
#endif
    }

  else
    {
      std::ofstream out_stream (file_name.c_str());
      this->write_implementation (out_stream);
    }
}

void UCDIO::read_implementation (std::istream & in)
{
  // This is a serial-only process for now;
  // the Mesh should be read on processor 0 and
  // broadcast later
  libmesh_assert_equal_to (MeshOutput<MeshBase>::mesh().processor_id(), 0);

  // Check input buffer
  libmesh_assert (in.good());

  MeshBase & mesh = MeshInput<MeshBase>::mesh();

  // Keep track of what kinds of elements this file contains
  elems_of_dimension.clear();
  elems_of_dimension.resize(4, false);

  this->skip_comment_lines (in, '#');

  unsigned int nNodes=0, nElem=0, dummy=0;

  in >> nNodes   // Read the number of nodes from the stream
     >> nElem    // Read the number of elements from the stream
     >> dummy
     >> dummy
     >> dummy;

  // Read the nodal coordinates. Note that UCD format always
  // stores (x,y,z), and in 2D z=0. We don't need to store this,
  // however.  So, we read in x,y,z for each node and make a point
  // in the proper way based on what dimension we're in
  {
    Point xyz;

    for (unsigned int i=0; i<nNodes; i++)
      {
        libmesh_assert (in.good());

        in >> dummy   // Point number
           >> xyz(0)  // x-coordinate value
           >> xyz(1)  // y-coordinate value
           >> xyz(2); // z-coordinate value

        // Build the node
        mesh.add_point (xyz, i);
      }
  }

  // Read the elements from the stream. Notice that the UCD node-numbering
  // scheme is 1-based, and we just created a 0-based scheme above
  // (which is of course what we want). So, when we read in the nodal
  // connectivity for each element we need to take 1 off the value of
  // each node so that we get the right thing.
  {
    unsigned int material_id=0, node=0;
    std::string type;

    for (unsigned int i=0; i<nElem; i++)
      {
        libmesh_assert (in.good());

        // The cell type can be either tri, quad, tet, hex, or prism.
        in >> dummy        // Cell number, means nothing to us
           >> material_id  // We'll use this for the element subdomain id.
           >> type;        // string describing cell type

        // Convert the UCD type string to a libmesh ElementType
        auto it = _reading_element_map.find(type);
        if (it == _reading_element_map.end())
          libmesh_error_msg("Unsupported element type = " << type);

        // Build the required type and release it into our custody.
        Elem * elem = Elem::build(it->second).release();

        for (unsigned int n=0; n<elem->n_nodes(); n++)
          {
            libmesh_assert (in.good());

            in >> node; // read the current node
            node -= 1;  // UCD is 1-based, so subtract

            libmesh_assert_less (node, mesh.n_nodes());

            // assign the node
            elem->set_node(n) = mesh.node_ptr(node);
          }

        elems_of_dimension[elem->dim()] = true;

        // Set the element's subdomain ID based on the material_id.
        elem->subdomain_id() = cast_int<subdomain_id_type>(material_id);

        // Add the element to the mesh
        elem->set_id(i);
        mesh.add_elem (elem);
      }

    // Set the mesh dimension to the largest encountered for an element
    for (unsigned char i=0; i!=4; ++i)
      if (elems_of_dimension[i])
        mesh.set_mesh_dimension(i);

#if LIBMESH_DIM < 3
    if (mesh.mesh_dimension() > LIBMESH_DIM)
      libmesh_error_msg("Cannot open dimension " \
                        << mesh.mesh_dimension() \
                        << " mesh file when configured without " \
                        << mesh.mesh_dimension() \
                        << "D support.");
#endif
  }
}

void UCDIO::write_implementation (std::ostream & out_stream)
{
  libmesh_assert (out_stream.good());

  const MeshBase & mesh = MeshOutput<MeshBase>::mesh();

  // UCD doesn't work any dimension except 3?
  if (mesh.mesh_dimension() != 3)
    libmesh_error_msg("Error: Can't write boundary elements for meshes of dimension less than 3. " \
                      << "Mesh dimension = " << mesh.mesh_dimension());

  // Write header
  this->write_header(out_stream, mesh, mesh.n_elem(), 0);

  // Write the node coordinates
  this->write_nodes(out_stream, mesh);

  // Write the elements
  this->write_interior_elems(out_stream, mesh);
}

void UCDIO::write_header(std::ostream & out_stream,
                         const MeshBase & mesh,
                         dof_id_type n_elems,
                         unsigned int n_vars)
{
  libmesh_assert (out_stream.good());
  // TODO: We could print out the libmesh revision used to write this file here.
  out_stream << "# For a description of the UCD format see the AVS Developer's guide.\n"
             << "#\n";

  // Write the mesh info
  out_stream << mesh.n_nodes() << " "
             << n_elems  << " "
             << n_vars << " "
             << " 0 0\n";
}

void UCDIO::write_nodes(std::ostream & out_stream,
                        const MeshBase & mesh)
{
  // 1-based node number for UCD
  unsigned int n=1;

  // Write the node coordinates
  for (auto & node : mesh.node_ptr_range())
    {
      libmesh_assert (out_stream.good());

      out_stream << n++ << "\t";
      node->write_unformatted(out_stream);
    }
}

void UCDIO::write_interior_elems(std::ostream & out_stream,
                                 const MeshBase & mesh)
{
  // 1-based element number for UCD
  unsigned int e=1;

  // Write element information
  for (const auto & elem : mesh.element_ptr_range())
    {
      libmesh_assert (out_stream.good());

      // Look up the corresponding UCD element type in the static map.
      const ElemType etype = elem->type();
      auto it = _writing_element_map.find(etype);
      if (it == _writing_element_map.end())
        libmesh_error_msg("Error: Unsupported ElemType " << etype << " for UCDIO.");

      // Write the element's subdomain ID as the UCD "material_id".
      out_stream << e++ << " " << elem->subdomain_id() << " " << it->second << "\t";
      elem->write_connectivity(out_stream, UCD);
    }
}

void UCDIO::write_nodal_data(const std::string & fname,
                             const std::vector<Number> & soln,
                             const std::vector<std::string> & names)
{
  const MeshBase & mesh = MeshOutput<MeshBase>::mesh();

  const dof_id_type n_elem = mesh.n_elem();

  // Only processor 0 does the writing
  if (mesh.processor_id())
    return;

  std::ofstream out_stream(fname.c_str());

  // UCD doesn't work in 1D
  libmesh_assert (mesh.mesh_dimension() != 1);

  // Write header
  this->write_header(out_stream,mesh,n_elem,
                     cast_int<unsigned int>(names.size()));

  // Write the node coordinates
  this->write_nodes(out_stream, mesh);

  // Write the elements
  this->write_interior_elems(out_stream, mesh);

  // Write the solution
  this->write_soln(out_stream, mesh, names, soln);
}

void UCDIO::write_soln(std::ostream & out_stream,
                       const MeshBase & mesh,
                       const std::vector<std::string> & names,
                       const std::vector<Number> & soln)
{
  libmesh_assert (out_stream.good());

  // First write out how many variables and how many components per variable
  out_stream << names.size();
  for (std::size_t i = 0; i < names.size(); i++)
    {
      libmesh_assert (out_stream.good());
      // Each named variable has only 1 component
      out_stream << " 1";
    }
  out_stream << std::endl;

  // Now write out variable names and units. Since we don't store units
  // We just write out dummy.
  for (const auto & name : names)
    {
      libmesh_assert (out_stream.good());
      out_stream << name << ", dummy" << std::endl;
    }

  // Now, for each node, write out the solution variables.
  // We use a 1-based node numbering for UCD.
  std::size_t nv = names.size();
  for (std::size_t n = 1; n <= mesh.n_nodes(); n++)
    {
      libmesh_assert (out_stream.good());
      out_stream << n;

      for (std::size_t var = 0; var != nv; var++)
        {
          std::size_t idx = nv*(n-1) + var;

          out_stream << " " << soln[idx];
        }
      out_stream << std::endl;
    }
}

} // namespace libMesh
<|endoftext|>