<commit_before>///////////////////////////////////////////////////////////////////////////////
//
// File: BlockMatrix.hpp
//
// For more information, please see: http://www.nektar.info
//
// The MIT License
//
// Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
// Department of Aeronautics, Imperial College London (UK), and Scientific
// Computing and Imaging Institute, University of Utah (USA).
//
// License for the specific language governing rights and limitations under
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// Description:
//
///////////////////////////////////////////////////////////////////////////////

#ifndef NEKTAR_LIB_UTILITIES_LINEAR_ALGEBRA_BLOCK_MATRIX_HPP
#define NEKTAR_LIB_UTILITIES_LINEAR_ALGEBRA_BLOCK_MATRIX_HPP

#include <LibUtilities/LinearAlgebra/MatrixBase.hpp>
#include <LibUtilities/BasicUtils/SharedArray.hpp>
#include <LibUtilities/LinearAlgebra/NekVector.hpp>
#include <LibUtilities/LinearAlgebra/FullMatrixStoragePolicy.hpp>
#include <LibUtilities/LinearAlgebra/DiagonalMatrixStoragePolicy.hpp>
#include <LibUtilities/LinearAlgebra/TriangularMatrixStoragePolicy.hpp>
#include <LibUtilities/LinearAlgebra/BandedMatrixStoragePolicy.hpp>

#include <boost/shared_ptr.hpp>

namespace Nektar
{
    template<typename DataType, typename InnerStorageType, typename InnerMatrixType, typename StorageType>
    class NekMatrix<NekMatrix<DataType, InnerStorageType, InnerMatrixType>, StorageType, BlockMatrixTag> : public ConstMatrix<typename NekMatrix<DataType, InnerStorageType, InnerMatrixType>::NumberType>
    {
        public:
            typedef NekMatrix<DataType, InnerStorageType, InnerMatrixType> InnerType;
            typedef NekMatrix<InnerType, StorageType, BlockMatrixTag> ThisType;
            typedef typename InnerType::NumberType NumberType;
            typedef ConstMatrix<NumberType> BaseType;

            // Each inner matrix type can possible return references or value types from GetValue.
            // Query the type here to find out.
            typedef typename InnerType::GetValueType GetValueType;
            typedef typename InnerType::ConstGetValueType ConstGetValueType;

        public:
            template<typename MatrixType>
            class iterator_base
            {
                public:
                    typedef typename MatrixType::InnerType IteratorInnerType;

                    // TODO
                    // This won't work if we want to specify the data as banded,
                    // because the data type for banded requires consturctor paramters.
                    // It should work for everything else.  We may need to slightly
                    // rethink the template parameters.
                    typedef MatrixStoragePolicy<NumberType, StorageType> StoragePolicy;

                public:
                    iterator_base(MatrixType& m, unsigned int curRow, unsigned int curCol) :
                        m_matrix(m),
                        m_curRow(curRow),
                        m_curColumn(curCol)
                    {
                    }

                    iterator_base(MatrixType& m) :
                        m_matrix(m),
                        m_curRow(std::numeric_limits<unsigned int>::max()),
                        m_curColumn(std::numeric_limits<unsigned int>::max())
                    {
                    }

                    iterator_base(const iterator_base<MatrixType>& rhs) :
                        m_matrix(rhs.m_matrix),
                        m_curRow(rhs.m_curRow),
                        m_curColumn(rhs.m_curColumn)
                    {
                    }

                    void operator++()
                    {
                        if( m_curRow != std::numeric_limits<unsigned int>::max() )
                        {
                            boost::tie(m_curRow, m_curColumn) = StoragePolicy::Advance(
                                m_matrix.GetRows(), m_matrix.GetColumns(), m_curRow, m_curColumn, m_data);
                        }
                    }

                    NumberType operator*()
                    {
                        return m_matrix(m_curRow, m_curColumn);
                    }

                    bool operator==(const iterator_base<MatrixType>& rhs)
                    {
                        return m_curRow == rhs.m_curRow && m_curColumn == rhs.m_curColumn;
                    }

                    bool operator!=(const iterator_base<MatrixType>& rhs)
                    {
                        return !(*this == rhs);
                    }

                private:
                    iterator_base<MatrixType>& operator=(const iterator_base<MatrixType>& rhs);

                    MatrixType& m_matrix;
                    //boost::shared_ptr<IteratorInnerType> m_curBlock;
                    unsigned int m_curRow;
                    unsigned int m_curColumn;
                    typename StoragePolicy::PolicySpecificDataHolderType m_data;
            };

            typedef iterator_base<ThisType> iterator;
            typedef iterator_base<const ThisType> const_iterator;

        public:
            NekMatrix() :
                BaseType(0,0),
                m_data(),
                m_rowSizes(),
                m_columnSizes(),
                m_storageSize(),
                m_numberOfBlockRows(0),
                m_numberOfBlockColumns(0)
            {
            }

            NekMatrix(unsigned int numberOfBlockRows, unsigned int numberOfBlockColumns,
                      unsigned int rowsPerBlock, unsigned int columnsPerBlock) :
                BaseType(numberOfBlockRows*rowsPerBlock, numberOfBlockColumns*columnsPerBlock),
                m_data(numberOfBlockRows, numberOfBlockColumns, boost::shared_ptr<InnerType>()),
                m_rowSizes(numberOfBlockRows),
                m_columnSizes(numberOfBlockColumns),
                m_storageSize(0),
                m_numberOfBlockRows(numberOfBlockRows),
                m_numberOfBlockColumns(numberOfBlockColumns)
            {
                m_storageSize = this->GetRows()*this->GetColumns();
                for(unsigned int i = 1; i <= numberOfBlockRows; ++i)
                {
                    m_rowSizes[i-1] = i*rowsPerBlock-1;
                }

                for(unsigned int i = 1; i <= numberOfBlockColumns; ++i)
                {
                    m_columnSizes[i-1] = i*columnsPerBlock-1;
                }
            }

            NekMatrix(unsigned int numberOfBlockRows, unsigned int numberOfBlockColumns,
                      unsigned int* rowsPerBlock, unsigned int* columnsPerBlock) :
                BaseType(std::accumulate(rowsPerBlock, rowsPerBlock + numberOfBlockRows, 0),
                         std::accumulate(columnsPerBlock, columnsPerBlock + numberOfBlockColumns, 0)),
                m_data(numberOfBlockRows, numberOfBlockColumns, boost::shared_ptr<InnerType>()),
                m_rowSizes(numberOfBlockRows),
                m_columnSizes(numberOfBlockColumns),
                m_storageSize(0),
                m_numberOfBlockRows(numberOfBlockRows),
                m_numberOfBlockColumns(numberOfBlockColumns)
            {
                m_storageSize = this->GetRows()*this->GetColumns();
                m_rowSizes[0] = rowsPerBlock[0] - 1;
                for(unsigned int i = 1; i < numberOfBlockRows; ++i)
                {
                    m_rowSizes[i] = rowsPerBlock[i] + m_rowSizes[i-1];
                }

                m_columnSizes[0] = columnsPerBlock[0] - 1;
                for(unsigned int i = 1; i < numberOfBlockColumns; ++i)
                {
                    m_columnSizes[i] = columnsPerBlock[i] + m_columnSizes[i-1];
                }
            }

            boost::shared_ptr<const InnerType> GetBlock(unsigned int row, unsigned int column) const
            {
                ASSERTL2(row < m_numberOfBlockRows, std::string("Row ") + boost::lexical_cast<std::string>(row) +
                    std::string(" requested in a block matrix with a maximum of ") + boost::lexical_cast<std::string>(m_numberOfBlockRows) +
                    std::string(" rows"));
                ASSERTL2(column < m_numberOfBlockColumns, std::string("Column ") + boost::lexical_cast<std::string>(column) +
                    std::string(" requested in a block matrix with a maximum of ") + boost::lexical_cast<std::string>(m_numberOfBlockColumns) +
                    std::string(" columns"));
                return m_data[row][column];
            }

            boost::shared_ptr<InnerType> GetBlock(unsigned int row, unsigned int column)
            {
                ASSERTL2(row < m_numberOfBlockRows, std::string("Row ") + boost::lexical_cast<std::string>(row) +
                    std::string(" requested in a block matrix with a maximum of ") + boost::lexical_cast<std::string>(m_numberOfBlockRows) +
                    std::string(" rows"));
                ASSERTL2(column < m_numberOfBlockColumns, std::string("Column ") + boost::lexical_cast<std::string>(column) +
                    std::string(" requested in a block matrix with a maximum of ") + boost::lexical_cast<std::string>(m_numberOfBlockColumns) +
                    std::string(" columns"));
                return m_data[row][column];
            }

            void SetBlock(unsigned int row, unsigned int column, boost::shared_ptr<InnerType>& m)
            {
                ASSERTL2(row < m_numberOfBlockRows, std::string("Row ") + boost::lexical_cast<std::string>(row) +
                    std::string(" requested in a block matrix with a maximum of ") + boost::lexical_cast<std::string>(m_numberOfBlockRows) +
                    std::string(" rows"));
                ASSERTL2(column < m_numberOfBlockColumns, std::string("Column ") + boost::lexical_cast<std::string>(column) +
                    std::string(" requested in a block matrix with a maximum of ") + boost::lexical_cast<std::string>(m_numberOfBlockColumns) +
                    std::string(" columns"));
                m_data[row][column] = m;
            }

            ConstGetValueType operator()(unsigned int row, unsigned int col) const
            {
                ASSERTL2(row < this->GetRows(), std::string("Row ") + boost::lexical_cast<std::string>(row) +
                    std::string(" requested in a matrix with a maximum of ") + boost::lexical_cast<std::string>(this->GetRows()) +
                    std::string(" rows"));
                ASSERTL2(col < this->GetColumns(), std::string("Column ") + boost::lexical_cast<std::string>(col) +
                    std::string(" requested in a matrix with a maximum of ") + boost::lexical_cast<std::string>(this->GetColumns()) +
                    std::string(" columns"));

                unsigned int blockRow = std::lower_bound(m_rowSizes.begin(), m_rowSizes.end(), row) - m_rowSizes.begin();
                unsigned int blockColumn = std::lower_bound(m_columnSizes.begin(), m_columnSizes.end(), col) - m_columnSizes.begin();
                unsigned int actualRow = row;
                if( blockRow > 0 )
                {
                    actualRow = row-(m_rowSizes[blockRow-1])-1;
                }

                unsigned int actualCol = col;
                if( blockColumn > 0 )
                {
                    actualCol = col-(m_columnSizes[blockColumn-1])-1;
                }

                const boost::shared_ptr<const InnerType> block = GetBlock(blockRow, blockColumn);
                if( block )
                {
                    return (*block)(actualRow, actualCol);
                }
                else
                {
                    return m_zeroElement;
                }
            }

            unsigned int GetStorageSize() const
            {
                return m_storageSize;
            }

            MatrixStorage GetStorageType() const
            {
                return static_cast<MatrixStorage>(ConvertToMatrixStorageEnum<StorageType>::Value);
            }

            unsigned int GetNumberOfBlockRows() const { return m_numberOfBlockRows; }
            unsigned int GetNumberOfBlockColumns() const { return m_numberOfBlockColumns; }

            iterator begin() { return iterator(*this, 0, 0); }
            iterator end() { return iterator(*this); }
            const_iterator begin() const { return const_iterator(*this, 0, 0); }
            const_iterator end() const { return const_iterator(*this); }

        public:

        private:
            virtual typename boost::call_traits<NumberType>::value_type v_GetValue(unsigned int row, unsigned int column) const
            {
                return (*this)(row, column);
            }

            virtual unsigned int v_GetStorageSize() const
            {
                return this->GetStorageSize();
            }

            virtual MatrixStorage v_GetStorageType() const
            {
                return this->GetStorageType();
            }

            Array<TwoD, boost::shared_ptr<InnerType> > m_data;
            Array<OneD, unsigned int> m_rowSizes;
            Array<OneD, unsigned int> m_columnSizes;
            unsigned int m_storageSize;
            unsigned int m_numberOfBlockRows;
            unsigned int m_numberOfBlockColumns;
            static NumberType m_zeroElement;
    };

    template<typename DataType, typename InnerStorageType, typename InnerMatrixType, typename StorageType>
    typename NekMatrix<NekMatrix<DataType, InnerStorageType, InnerMatrixType>, StorageType, BlockMatrixTag>::NumberType
    NekMatrix<NekMatrix<DataType, InnerStorageType, InnerMatrixType>, StorageType, BlockMatrixTag>::m_zeroElement(0);
}

#endif //NEKTAR_LIB_UTILITIES_LINEAR_ALGEBRA_BLOCK_MATRIX_HPP
<commit_msg>Added methods to find the number of rows/columns in a particular block.<commit_after>///////////////////////////////////////////////////////////////////////////////
//
// File: BlockMatrix.hpp
//
// For more information, please see: http://www.nektar.info
//
// The MIT License
//
// Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
// Department of Aeronautics, Imperial College London (UK), and Scientific
// Computing and Imaging Institute, University of Utah (USA).
//
// License for the specific language governing rights and limitations under
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// Description:
//
///////////////////////////////////////////////////////////////////////////////

#ifndef NEKTAR_LIB_UTILITIES_LINEAR_ALGEBRA_BLOCK_MATRIX_HPP
#define NEKTAR_LIB_UTILITIES_LINEAR_ALGEBRA_BLOCK_MATRIX_HPP

#include <LibUtilities/LinearAlgebra/MatrixBase.hpp>
#include <LibUtilities/BasicUtils/SharedArray.hpp>
#include <LibUtilities/LinearAlgebra/NekVector.hpp>
#include <LibUtilities/LinearAlgebra/FullMatrixStoragePolicy.hpp>
#include <LibUtilities/LinearAlgebra/DiagonalMatrixStoragePolicy.hpp>
#include <LibUtilities/LinearAlgebra/TriangularMatrixStoragePolicy.hpp>
#include <LibUtilities/LinearAlgebra/BandedMatrixStoragePolicy.hpp>

#include <boost/shared_ptr.hpp>

namespace Nektar
{
    template<typename DataType, typename InnerStorageType, typename InnerMatrixType, typename StorageType>
    class NekMatrix<NekMatrix<DataType, InnerStorageType, InnerMatrixType>, StorageType, BlockMatrixTag> : public ConstMatrix<typename NekMatrix<DataType, InnerStorageType, InnerMatrixType>::NumberType>
    {
        public:
            typedef NekMatrix<DataType, InnerStorageType, InnerMatrixType> InnerType;
            typedef NekMatrix<InnerType, StorageType, BlockMatrixTag> ThisType;
            typedef typename InnerType::NumberType NumberType;
            typedef ConstMatrix<NumberType> BaseType;

            // Each inner matrix type can possible return references or value types from GetValue.
            // Query the type here to find out.
            typedef typename InnerType::GetValueType GetValueType;
            typedef typename InnerType::ConstGetValueType ConstGetValueType;

        public:
            template<typename MatrixType>
            class iterator_base
            {
                public:
                    typedef typename MatrixType::InnerType IteratorInnerType;

                    // TODO
                    // This won't work if we want to specify the data as banded,
                    // because the data type for banded requires consturctor paramters.
                    // It should work for everything else.  We may need to slightly
                    // rethink the template parameters.
                    typedef MatrixStoragePolicy<NumberType, StorageType> StoragePolicy;

                public:
                    iterator_base(MatrixType& m, unsigned int curRow, unsigned int curCol) :
                        m_matrix(m),
                        m_curRow(curRow),
                        m_curColumn(curCol)
                    {
                    }

                    iterator_base(MatrixType& m) :
                        m_matrix(m),
                        m_curRow(std::numeric_limits<unsigned int>::max()),
                        m_curColumn(std::numeric_limits<unsigned int>::max())
                    {
                    }

                    iterator_base(const iterator_base<MatrixType>& rhs) :
                        m_matrix(rhs.m_matrix),
                        m_curRow(rhs.m_curRow),
                        m_curColumn(rhs.m_curColumn)
                    {
                    }

                    void operator++()
                    {
                        if( m_curRow != std::numeric_limits<unsigned int>::max() )
                        {
                            boost::tie(m_curRow, m_curColumn) = StoragePolicy::Advance(
                                m_matrix.GetRows(), m_matrix.GetColumns(), m_curRow, m_curColumn, m_data);
                        }
                    }

                    NumberType operator*()
                    {
                        return m_matrix(m_curRow, m_curColumn);
                    }

                    bool operator==(const iterator_base<MatrixType>& rhs)
                    {
                        return m_curRow == rhs.m_curRow && m_curColumn == rhs.m_curColumn;
                    }

                    bool operator!=(const iterator_base<MatrixType>& rhs)
                    {
                        return !(*this == rhs);
                    }

                private:
                    iterator_base<MatrixType>& operator=(const iterator_base<MatrixType>& rhs);

                    MatrixType& m_matrix;
                    //boost::shared_ptr<IteratorInnerType> m_curBlock;
                    unsigned int m_curRow;
                    unsigned int m_curColumn;
                    typename StoragePolicy::PolicySpecificDataHolderType m_data;
            };

            typedef iterator_base<ThisType> iterator;
            typedef iterator_base<const ThisType> const_iterator;

        public:
            NekMatrix() :
                BaseType(0,0),
                m_data(),
                m_rowSizes(),
                m_columnSizes(),
                m_storageSize(),
                m_numberOfBlockRows(0),
                m_numberOfBlockColumns(0)
            {
            }

            NekMatrix(unsigned int numberOfBlockRows, unsigned int numberOfBlockColumns,
                      unsigned int rowsPerBlock, unsigned int columnsPerBlock) :
                BaseType(numberOfBlockRows*rowsPerBlock, numberOfBlockColumns*columnsPerBlock),
                m_data(numberOfBlockRows, numberOfBlockColumns, boost::shared_ptr<InnerType>()),
                m_rowSizes(numberOfBlockRows),
                m_columnSizes(numberOfBlockColumns),
                m_storageSize(0),
                m_numberOfBlockRows(numberOfBlockRows),
                m_numberOfBlockColumns(numberOfBlockColumns)
            {
                m_storageSize = this->GetRows()*this->GetColumns();
                for(unsigned int i = 1; i <= numberOfBlockRows; ++i)
                {
                    m_rowSizes[i-1] = i*rowsPerBlock-1;
                }

                for(unsigned int i = 1; i <= numberOfBlockColumns; ++i)
                {
                    m_columnSizes[i-1] = i*columnsPerBlock-1;
                }
            }

            NekMatrix(unsigned int numberOfBlockRows, unsigned int numberOfBlockColumns,
                      unsigned int* rowsPerBlock, unsigned int* columnsPerBlock) :
                BaseType(std::accumulate(rowsPerBlock, rowsPerBlock + numberOfBlockRows, 0),
                         std::accumulate(columnsPerBlock, columnsPerBlock + numberOfBlockColumns, 0)),
                m_data(numberOfBlockRows, numberOfBlockColumns, boost::shared_ptr<InnerType>()),
                m_rowSizes(numberOfBlockRows),
                m_columnSizes(numberOfBlockColumns),
                m_storageSize(0),
                m_numberOfBlockRows(numberOfBlockRows),
                m_numberOfBlockColumns(numberOfBlockColumns)
            {
                m_storageSize = this->GetRows()*this->GetColumns();
                m_rowSizes[0] = rowsPerBlock[0] - 1;
                for(unsigned int i = 1; i < numberOfBlockRows; ++i)
                {
                    m_rowSizes[i] = rowsPerBlock[i] + m_rowSizes[i-1];
                }

                m_columnSizes[0] = columnsPerBlock[0] - 1;
                for(unsigned int i = 1; i < numberOfBlockColumns; ++i)
                {
                    m_columnSizes[i] = columnsPerBlock[i] + m_columnSizes[i-1];
                }
            }

            boost::shared_ptr<const InnerType> GetBlock(unsigned int row, unsigned int column) const
            {
                ASSERTL2(row < m_numberOfBlockRows, std::string("Row ") + boost::lexical_cast<std::string>(row) +
                    std::string(" requested in a block matrix with a maximum of ") + boost::lexical_cast<std::string>(m_numberOfBlockRows) +
                    std::string(" rows"));
                ASSERTL2(column < m_numberOfBlockColumns, std::string("Column ") + boost::lexical_cast<std::string>(column) +
                    std::string(" requested in a block matrix with a maximum of ") + boost::lexical_cast<std::string>(m_numberOfBlockColumns) +
                    std::string(" columns"));
                return m_data[row][column];
            }

            boost::shared_ptr<InnerType> GetBlock(unsigned int row, unsigned int column)
            {
                ASSERTL2(row < m_numberOfBlockRows, std::string("Row ") + boost::lexical_cast<std::string>(row) +
                    std::string(" requested in a block matrix with a maximum of ") + boost::lexical_cast<std::string>(m_numberOfBlockRows) +
                    std::string(" rows"));
                ASSERTL2(column < m_numberOfBlockColumns, std::string("Column ") + boost::lexical_cast<std::string>(column) +
                    std::string(" requested in a block matrix with a maximum of ") + boost::lexical_cast<std::string>(m_numberOfBlockColumns) +
                    std::string(" columns"));
                return m_data[row][column];
            }

            void SetBlock(unsigned int row, unsigned int column, boost::shared_ptr<InnerType>& m)
            {
                ASSERTL2(row < m_numberOfBlockRows, std::string("Row ") + boost::lexical_cast<std::string>(row) +
                    std::string(" requested in a block matrix with a maximum of ") + boost::lexical_cast<std::string>(m_numberOfBlockRows) +
                    std::string(" rows"));
                ASSERTL2(column < m_numberOfBlockColumns, std::string("Column ") + boost::lexical_cast<std::string>(column) +
                    std::string(" requested in a block matrix with a maximum of ") + boost::lexical_cast<std::string>(m_numberOfBlockColumns) +
                    std::string(" columns"));
                m_data[row][column] = m;
            }

            ConstGetValueType operator()(unsigned int row, unsigned int col) const
            {
                ASSERTL2(row < this->GetRows(), std::string("Row ") + boost::lexical_cast<std::string>(row) +
                    std::string(" requested in a matrix with a maximum of ") + boost::lexical_cast<std::string>(this->GetRows()) +
                    std::string(" rows"));
                ASSERTL2(col < this->GetColumns(), std::string("Column ") + boost::lexical_cast<std::string>(col) +
                    std::string(" requested in a matrix with a maximum of ") + boost::lexical_cast<std::string>(this->GetColumns()) +
                    std::string(" columns"));

                unsigned int blockRow = std::lower_bound(m_rowSizes.begin(), m_rowSizes.end(), row) - m_rowSizes.begin();
                unsigned int blockColumn = std::lower_bound(m_columnSizes.begin(), m_columnSizes.end(), col) - m_columnSizes.begin();
                unsigned int actualRow = row;
                if( blockRow > 0 )
                {
                    actualRow = row-(m_rowSizes[blockRow-1])-1;
                }

                unsigned int actualCol = col;
                if( blockColumn > 0 )
                {
                    actualCol = col-(m_columnSizes[blockColumn-1])-1;
                }

                const boost::shared_ptr<const InnerType> block = GetBlock(blockRow, blockColumn);
                if( block )
                {
                    return (*block)(actualRow, actualCol);
                }
                else
                {
                    return m_zeroElement;
                }
            }

            unsigned int GetStorageSize() const
            {
                return m_storageSize;
            }

            MatrixStorage GetStorageType() const
            {
                return static_cast<MatrixStorage>(ConvertToMatrixStorageEnum<StorageType>::Value);
            }

            unsigned int GetNumberOfBlockRows() const { return m_numberOfBlockRows; }
            unsigned int GetNumberOfBlockColumns() const { return m_numberOfBlockColumns; }

            unsigned int GetNumberOfRowsInBlockRow(unsigned int blockRow) const
            {
                ASSERTL2(row < m_numberOfBlockRows, std::string("Block Row ") + boost::lexical_cast<std::string>(row) +
                    std::string(" requested in a matrix with a maximum of ") + boost::lexical_cast<std::string>(m_numberOfBlockRows) +
                    std::string(" block rows"));
                if( blockRow == 0 )
                {
                    return m_rowSizes[blockRow]+1;
                }
                else
                {
                    return m_rowSizes[blockRow] - m_rowSizes[blockRow-1];
                }

            }

            unsigned int GetNumberOfColumnsInBlockColumn(unsigned int blockCol) const
            {
                ASSERTL2(row < m_numberOfBlockColumns, std::string("Block column ") + boost::lexical_cast<std::string>(row) +
                    std::string(" requested in a matrix with a maximum of ") + boost::lexical_cast<std::string>(m_numberOfBlockColumns) +
                    std::string(" block columns"));
                if( blockCol == 0 )
                {
                    return m_columnSizes[blockCol]+1;
                }
                else
                {
                    return m_columnSizes[blockCol] - m_columnSizes[blockCol-1];
                }
            }

            iterator begin() { return iterator(*this, 0, 0); }
            iterator end() { return iterator(*this); }
            const_iterator begin() const { return const_iterator(*this, 0, 0); }
            const_iterator end() const { return const_iterator(*this); }

        public:

        private:
            virtual typename boost::call_traits<NumberType>::value_type v_GetValue(unsigned int row, unsigned int column) const
            {
                return (*this)(row, column);
            }

            virtual unsigned int v_GetStorageSize() const
            {
                return this->GetStorageSize();
            }

            virtual MatrixStorage v_GetStorageType() const
            {
                return this->GetStorageType();
            }

            Array<TwoD, boost::shared_ptr<InnerType> > m_data;
            Array<OneD, unsigned int> m_rowSizes;
            Array<OneD, unsigned int> m_columnSizes;
            unsigned int m_storageSize;
            unsigned int m_numberOfBlockRows;
            unsigned int m_numberOfBlockColumns;
            static NumberType m_zeroElement;
    };

    template<typename DataType, typename InnerStorageType, typename InnerMatrixType, typename StorageType>
    typename NekMatrix<NekMatrix<DataType, InnerStorageType, InnerMatrixType>, StorageType, BlockMatrixTag>::NumberType
    NekMatrix<NekMatrix<DataType, InnerStorageType, InnerMatrixType>, StorageType, BlockMatrixTag>::m_zeroElement(0);
}

#endif //NEKTAR_LIB_UTILITIES_LINEAR_ALGEBRA_BLOCK_MATRIX_HPP
<|endoftext|>


<commit_before>// InputXML.cpp
// Implements XML input handling class
#include <iostream>
#include <string>
#include <sys/stat.h>

#include "InputXML.h"

#include "Timer.h"
#include "Env.h"
#include "CycException.h"
#include "Model.h"
#include "Commodity.h"
#include "Material.h"

using namespace std;

InputXML* InputXML::instance_ = 0;

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string InputXML::main_schema_ = ENV->getCyclusPath() + "/Data/cyclus.rng";

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
InputXML::InputXML() {
  cur_ns_ = "";
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
InputXML* InputXML::Instance() {
  main_schema_ = ENV->getCyclusPath() + "/Data/cyclus.rng";

  if (0 == instance_)
  instance_ = new InputXML();

  return instance_;

}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
xmlDocPtr InputXML::validate_file(xmlFileInfo *fileInfo) {
  xmlRelaxNGParserCtxtPtr ctxt = xmlRelaxNGNewParserCtxt(fileInfo->schema->c_str());
  if (NULL == ctxt)
  throw CycParseException("Failed to generate parser from schema: " + *(fileInfo->schema));

  xmlRelaxNGPtr schema = xmlRelaxNGParse(ctxt);

  xmlRelaxNGValidCtxtPtr vctxt = xmlRelaxNGNewValidCtxt(schema);

  xmlDocPtr doc = xmlReadFile(fileInfo->filename.c_str(), NULL,0);
  if (NULL == doc) {
    throw CycParseException("Failed to parse: " + fileInfo->filename);
  }

  if (xmlRelaxNGValidateDoc(vctxt,doc))
    throw CycParseException("Invalid XML file; file: "
      + fileInfo->filename
      + " does not validate against schema "
      + *(fileInfo->schema));
  else
    cerr << "File " << fileInfo->filename << " is valid against schema "
    << *(fileInfo->schema) << endl;

  /// free up some data

  return doc;

}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void InputXML::stripCurNS() {

  if ("" == cur_ns_)
  throw CycParseException("Unable to strip tokens from an empty namespace.");

  string::iterator pos = cur_ns_.end();
  cur_ns_.erase(--pos);

  size_t delimeter_pos = cur_ns_.rfind(':');

  if (string::npos != delimeter_pos)
  cur_ns_.erase(delimeter_pos);
  else
  cur_ns_.erase();

}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void InputXML::load_file(std::string filename) {
  // double check that the file exists
  if(filename=="") {
    throw CycIOException("No input filename was given");
  } else {
    FILE* file = fopen(filename.c_str(),"r");
    if(file == NULL) {
      throw CycIOException("The file cannot be loaded because it has not been found.");
    }
    fclose(file);
  }

  curFilePtr = new xmlFileInfo;

  xmlFileInfo &inputFile = *curFilePtr;

  inputFile.filename = filename;
  inputFile.schema = &main_schema_;
  inputFile.doc = validate_file(&inputFile);

  /* Create xpath evaluation context */
  inputFile.xpathCtxt = xmlXPathNewContext(inputFile.doc);
  if(inputFile.xpathCtxt == NULL) {
    fprintf(stderr,"Error: unable to create new xpath context \n");
  }

  Commodity::load_commodities();

  Material::load_recipes();

  Model::load_converters();
  Model::load_markets();
  Model::load_facilities();
  Model::load_regions();
  Model::load_institutions();

  TI->load_simulation();

  // delete/free mem

}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void InputXML::load_recipebook(std::string filename) {
  /// store parent file info
  fileStack_.push(curFilePtr);

  curFilePtr = new xmlFileInfo;
  xmlFileInfo &recipebook = *curFilePtr;

  recipebook.filename = filename;
  recipebook.schema = &main_schema_;
  recipebook.doc = validate_file(&recipebook);
  recipebook.xpathCtxt = xmlXPathNewContext(recipebook.doc);

  Material::load_recipes();

  // get rid of recipebook, freeing memory
  delete curFilePtr;

  /// restore parent file info
  curFilePtr = fileStack_.top();
  fileStack_.pop();

}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void InputXML::load_facilitycatalog(std::string filename) {
  /// store parent file info
  fileStack_.push(curFilePtr);

  curFilePtr = new xmlFileInfo;
  xmlFileInfo &facilitycatalog = *curFilePtr;

  facilitycatalog.filename = filename;
  facilitycatalog.schema = &main_schema_;
  facilitycatalog.doc = validate_file(&facilitycatalog);
  facilitycatalog.xpathCtxt = xmlXPathNewContext(facilitycatalog.doc);

  /// load here???
  Model::load_facilities();

  // get rid of facilitycatalog, freeing memory
  delete curFilePtr;

  /// restore parent file info
  curFilePtr = fileStack_.top();
  fileStack_.pop();

}

xmlNodeSetPtr InputXML::get_xpath_elements(xmlNodePtr cur,const char* expression) {

  xmlXPathContextPtr xpathCtxt = curFilePtr->xpathCtxt;
  xpathCtxt->node = cur;

  /* Evaluate xpath expression */
  xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression((const xmlChar*)expression, xpathCtxt);
  if(xpathObj == NULL) {
    fprintf(stderr,"Error: unable to evaluate xpath expression \"%s\"\n", expression);
    xmlXPathFreeContext(xpathCtxt);
  }

  return xpathObj->nodesetval;

  // when and how to cleanup memory allocation?

}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
xmlNodePtr InputXML::get_xpath_element(xmlNodePtr cur,const char* expression) {

  xmlXPathContextPtr xpathCtxt = curFilePtr->xpathCtxt;
  xpathCtxt->node = cur;

  /* Evaluate xpath expression */
  xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression((const xmlChar*)expression, xpathCtxt);
  if(xpathObj == NULL) {
    fprintf(stderr,"Error: unable to evaluate xpath expression \"%s\"\n", expression);
    xmlXPathFreeContext(xpathCtxt);
  }

  return xpathObj->nodesetval->nodeTab[0];

  // when and how to cleanup memory allocation?

}

const char* InputXML::get_xpath_content(xmlNodePtr cur,const char* expression) {

  xmlXPathContextPtr xpathCtxt = curFilePtr->xpathCtxt;
  xpathCtxt->node = cur;

  /* Evaluate xpath expression */
  xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression((const xmlChar*)expression, xpathCtxt);
  if(xpathObj == NULL) {
    fprintf(stderr,"Error: unable to evaluate xpath expression \"%s\"\n", expression);
    xmlXPathFreeContext(xpathCtxt);
  }

  return (const char*)(xpathObj->nodesetval->nodeTab[0]->children->content);

  // when and how to cleanup memory allocation?

}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const char* InputXML::get_xpath_name(xmlNodePtr cur,const char* expression) {

  xmlXPathContextPtr xpathCtxt = curFilePtr->xpathCtxt;
  xpathCtxt->node = cur;

  /* Evaluate xpath expression */
  xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression((const xmlChar*)expression, xpathCtxt);
  if(xpathObj == NULL) {
    fprintf(stderr,"Error: unable to evaluate xpath expression \"%s\"\n", expression);
    xmlXPathFreeContext(xpathCtxt);
  }

  return (const char*)(xpathObj->nodesetval->nodeTab[0]->name);

  // when and how to cleanup memory allocation?

}

<commit_msg>This addresses the platform-dependent issue introduced in r432 in which one static variable referenced another. The order in which they're initialized is not consistent among compilers.  My compiler/linker on OSX was trying to initialize InputXML::main_schema_ before Env::path_from_cwd_to_cyclus_ .<commit_after>// InputXML.cpp
// Implements XML input handling class
#include <iostream>
#include <string>
#include <sys/stat.h>

#include "InputXML.h"

#include "Timer.h"
#include "Env.h"
#include "CycException.h"
#include "Model.h"
#include "Commodity.h"
#include "Material.h"

using namespace std;

InputXML* InputXML::instance_ = 0;

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string InputXML::main_schema_ = "./Data/cyclus.rng";

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
InputXML::InputXML() {
  cur_ns_ = "";
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
InputXML* InputXML::Instance() {
  main_schema_ = ENV->getCyclusPath() + "/Data/cyclus.rng";

  if (0 == instance_)
  instance_ = new InputXML();

  return instance_;

}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
xmlDocPtr InputXML::validate_file(xmlFileInfo *fileInfo) {
  xmlRelaxNGParserCtxtPtr ctxt = xmlRelaxNGNewParserCtxt(fileInfo->schema->c_str());
  if (NULL == ctxt)
  throw CycParseException("Failed to generate parser from schema: " + *(fileInfo->schema));

  xmlRelaxNGPtr schema = xmlRelaxNGParse(ctxt);

  xmlRelaxNGValidCtxtPtr vctxt = xmlRelaxNGNewValidCtxt(schema);

  xmlDocPtr doc = xmlReadFile(fileInfo->filename.c_str(), NULL,0);
  if (NULL == doc) {
    throw CycParseException("Failed to parse: " + fileInfo->filename);
  }

  if (xmlRelaxNGValidateDoc(vctxt,doc))
    throw CycParseException("Invalid XML file; file: "
      + fileInfo->filename
      + " does not validate against schema "
      + *(fileInfo->schema));
  else
    cerr << "File " << fileInfo->filename << " is valid against schema "
    << *(fileInfo->schema) << endl;

  /// free up some data

  return doc;

}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void InputXML::stripCurNS() {

  if ("" == cur_ns_)
  throw CycParseException("Unable to strip tokens from an empty namespace.");

  string::iterator pos = cur_ns_.end();
  cur_ns_.erase(--pos);

  size_t delimeter_pos = cur_ns_.rfind(':');

  if (string::npos != delimeter_pos)
  cur_ns_.erase(delimeter_pos);
  else
  cur_ns_.erase();

}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void InputXML::load_file(std::string filename) {
  // double check that the file exists
  if(filename=="") {
    throw CycIOException("No input filename was given");
  } else {
    FILE* file = fopen(filename.c_str(),"r");
    if(file == NULL) {
      throw CycIOException("The file cannot be loaded because it has not been found.");
    }
    fclose(file);
  }

  curFilePtr = new xmlFileInfo;

  xmlFileInfo &inputFile = *curFilePtr;

  inputFile.filename = filename;
  inputFile.schema = &main_schema_;
  inputFile.doc = validate_file(&inputFile);

  /* Create xpath evaluation context */
  inputFile.xpathCtxt = xmlXPathNewContext(inputFile.doc);
  if(inputFile.xpathCtxt == NULL) {
    fprintf(stderr,"Error: unable to create new xpath context \n");
  }

  Commodity::load_commodities();

  Material::load_recipes();

  Model::load_converters();
  Model::load_markets();
  Model::load_facilities();
  Model::load_regions();
  Model::load_institutions();

  TI->load_simulation();

  // delete/free mem

}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void InputXML::load_recipebook(std::string filename) {
  /// store parent file info
  fileStack_.push(curFilePtr);

  curFilePtr = new xmlFileInfo;
  xmlFileInfo &recipebook = *curFilePtr;

  recipebook.filename = filename;
  recipebook.schema = &main_schema_;
  recipebook.doc = validate_file(&recipebook);
  recipebook.xpathCtxt = xmlXPathNewContext(recipebook.doc);

  Material::load_recipes();

  // get rid of recipebook, freeing memory
  delete curFilePtr;

  /// restore parent file info
  curFilePtr = fileStack_.top();
  fileStack_.pop();

}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void InputXML::load_facilitycatalog(std::string filename) {
  /// store parent file info
  fileStack_.push(curFilePtr);

  curFilePtr = new xmlFileInfo;
  xmlFileInfo &facilitycatalog = *curFilePtr;

  facilitycatalog.filename = filename;
  facilitycatalog.schema = &main_schema_;
  facilitycatalog.doc = validate_file(&facilitycatalog);
  facilitycatalog.xpathCtxt = xmlXPathNewContext(facilitycatalog.doc);

  /// load here???
  Model::load_facilities();

  // get rid of facilitycatalog, freeing memory
  delete curFilePtr;

  /// restore parent file info
  curFilePtr = fileStack_.top();
  fileStack_.pop();

}

xmlNodeSetPtr InputXML::get_xpath_elements(xmlNodePtr cur,const char* expression) {

  xmlXPathContextPtr xpathCtxt = curFilePtr->xpathCtxt;
  xpathCtxt->node = cur;

  /* Evaluate xpath expression */
  xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression((const xmlChar*)expression, xpathCtxt);
  if(xpathObj == NULL) {
    fprintf(stderr,"Error: unable to evaluate xpath expression \"%s\"\n", expression);
    xmlXPathFreeContext(xpathCtxt);
  }

  return xpathObj->nodesetval;

  // when and how to cleanup memory allocation?

}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
xmlNodePtr InputXML::get_xpath_element(xmlNodePtr cur,const char* expression) {

  xmlXPathContextPtr xpathCtxt = curFilePtr->xpathCtxt;
  xpathCtxt->node = cur;

  /* Evaluate xpath expression */
  xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression((const xmlChar*)expression, xpathCtxt);
  if(xpathObj == NULL) {
    fprintf(stderr,"Error: unable to evaluate xpath expression \"%s\"\n", expression);
    xmlXPathFreeContext(xpathCtxt);
  }

  return xpathObj->nodesetval->nodeTab[0];

  // when and how to cleanup memory allocation?

}

const char* InputXML::get_xpath_content(xmlNodePtr cur,const char* expression) {

  xmlXPathContextPtr xpathCtxt = curFilePtr->xpathCtxt;
  xpathCtxt->node = cur;

  /* Evaluate xpath expression */
  xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression((const xmlChar*)expression, xpathCtxt);
  if(xpathObj == NULL) {
    fprintf(stderr,"Error: unable to evaluate xpath expression \"%s\"\n", expression);
    xmlXPathFreeContext(xpathCtxt);
  }

  return (const char*)(xpathObj->nodesetval->nodeTab[0]->children->content);

  // when and how to cleanup memory allocation?

}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const char* InputXML::get_xpath_name(xmlNodePtr cur,const char* expression) {

  xmlXPathContextPtr xpathCtxt = curFilePtr->xpathCtxt;
  xpathCtxt->node = cur;

  /* Evaluate xpath expression */
  xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression((const xmlChar*)expression, xpathCtxt);
  if(xpathObj == NULL) {
    fprintf(stderr,"Error: unable to evaluate xpath expression \"%s\"\n", expression);
    xmlXPathFreeContext(xpathCtxt);
  }

  return (const char*)(xpathObj->nodesetval->nodeTab[0]->name);

  // when and how to cleanup memory allocation?

}

<|endoftext|>


<commit_before>#include "Interval.h"
#include "IROperator.h"
#include "IREquality.h"

namespace Halide {
namespace Internal {

// This is called repeatedly by bounds inference and the solver to
// build large expressions, so we want to simplify eagerly to avoid
// monster expressions.
Expr Interval::make_max(Expr a, Expr b) {
    if (a.same_as(b)) return a;

    // Deal with infinities
    if (a.same_as(Interval::pos_inf)) return a;
    if (b.same_as(Interval::pos_inf)) return b;
    if (a.same_as(Interval::neg_inf)) return b;
    if (b.same_as(Interval::neg_inf)) return a;

    // Constant fold
    const int64_t *ia = as_const_int(a);
    const int64_t *ib = as_const_int(b);
    const uint64_t *ua = as_const_uint(a);
    const uint64_t *ub = as_const_uint(b);
    const double *fa = as_const_float(a);
    const double *fb = as_const_float(b);
    if (ia && ib) return (*ia > *ib) ? a : b;
    if (ua && ub) return (*ua > *ub) ? a : b;
    if (fa && fb) return (*fa > *fb) ? a : b;

    // Balance trees to the left, with constants pushed rightwards
    const Max *ma = a.as<Max>();
    const Max *mb = b.as<Max>();
    if (mb && !ma) {
        std::swap(ma, mb);
        std::swap(a, b);
    }
    if (ma && is_const(ma->b) && is_const(b)) {
        return Interval::make_max(ma->a, Interval::make_max(ma->b, b));
    }
    if (ma && (ma->a.same_as(b) || ma->b.same_as(b))) {
        // b is already represented in a
        return a;
    }

    return Max::make(a, b);
}

Expr Interval::make_min(Expr a, Expr b) {
    if (a.same_as(b)) return a;

    // Deal with infinities
    if (a.same_as(Interval::pos_inf)) return b;
    if (b.same_as(Interval::pos_inf)) return a;
    if (a.same_as(Interval::neg_inf)) return a;
    if (b.same_as(Interval::neg_inf)) return b;

    // Constant fold
    const int64_t *ia = as_const_int(a);
    const int64_t *ib = as_const_int(b);
    const uint64_t *ua = as_const_uint(a);
    const uint64_t *ub = as_const_uint(b);
    const double *fa = as_const_float(a);
    const double *fb = as_const_float(b);
    if (ia && ib) return (*ia > *ib) ? b : a;
    if (ua && ub) return (*ua > *ub) ? b : a;
    if (fa && fb) return (*fa > *fb) ? b : a;

    // Balance trees to the left, with constants pushed rightwards
    const Min *ma = a.as<Min>();
    const Min *mb = b.as<Min>();
    if (mb && !ma) {
        std::swap(ma, mb);
        std::swap(a, b);
    }
    if (ma && is_const(ma->b) && is_const(b)) {
        return Interval::make_min(ma->a, Interval::make_min(ma->b, b));
    }
    if (ma && (ma->a.same_as(b) || ma->b.same_as(b))) {
        // b is already represented in a
        return a;
    }

    return Min::make(a, b);
}

void Interval::include(const Interval &i) {
    max = Interval::make_max(max, i.max);
    min = Interval::make_min(min, i.min);
}

void Interval::include(Expr e) {
    max = Interval::make_max(max, e);
    min = Interval::make_min(min, e);
}

Interval Interval::make_union(const Interval &a, const Interval &b) {
    Interval result = a;
    result.include(b);
    return result;
}

Interval Interval::make_intersection(const Interval &a, const Interval &b) {
    return Interval(Interval::make_max(a.min, b.min),
                    Interval::make_min(a.max, b.max));
}

// Use Handle types for positive and negative infinity, to prevent
// accidentally doing arithmetic on them.
Expr Interval::pos_inf = Variable::make(Handle(), "pos_inf");
Expr Interval::neg_inf = Variable::make(Handle(), "neg_inf");

namespace {
void check(Interval result, Interval expected, int line) {
    internal_assert(equal(result.min, expected.min) &&
                    equal(result.max, expected.max))
        << "Interval test on line " << line << " failed\n"
        << "  Expected [" << expected.min << ", " << expected.max << "]\n"
        << "  Got      [" << result.min << ", " << result.max << "]\n";
}
}

void interval_test() {
    Interval e = Interval::everything();
    Interval n = Interval::nothing();
    Expr x = Variable::make(Int(32), "x");
    Interval xp{x, Interval::pos_inf};
    Interval xn{Interval::neg_inf, x};
    Interval xx{x, x};

    internal_assert(e.is_everything());
    internal_assert(!e.has_upper_bound());
    internal_assert(!e.has_lower_bound());
    internal_assert(!e.is_empty());
    internal_assert(!e.is_bounded());
    internal_assert(!e.is_single_point());

    internal_assert(!n.is_everything());
    internal_assert(!n.has_upper_bound());
    internal_assert(!n.has_lower_bound());
    internal_assert(n.is_empty());
    internal_assert(!n.is_bounded());
    internal_assert(!n.is_single_point());

    internal_assert(!xp.is_everything());
    internal_assert(!xp.has_upper_bound());
    internal_assert(xp.has_lower_bound());
    internal_assert(!xp.is_empty());
    internal_assert(!xp.is_bounded());
    internal_assert(!xp.is_single_point());

    internal_assert(!xn.is_everything());
    internal_assert(xn.has_upper_bound());
    internal_assert(!xn.has_lower_bound());
    internal_assert(!xn.is_empty());
    internal_assert(!xn.is_bounded());
    internal_assert(!xn.is_single_point());

    internal_assert(!xx.is_everything());
    internal_assert(xx.has_upper_bound());
    internal_assert(xx.has_lower_bound());
    internal_assert(!xx.is_empty());
    internal_assert(xx.is_bounded());
    internal_assert(xx.is_single_point());

    check(Interval::make_union(xp, xn), e, __LINE__);
    check(Interval::make_union(e, xn), e, __LINE__);
    check(Interval::make_union(xn, e), e, __LINE__);
    check(Interval::make_union(xn, n), xn, __LINE__);
    check(Interval::make_union(n, xp), xp, __LINE__);
    check(Interval::make_union(xp, xp), xp, __LINE__);

    check(Interval::make_intersection(xp, xn), Interval::single_point(x), __LINE__);
    check(Interval::make_intersection(e, xn), xn, __LINE__);
    check(Interval::make_intersection(xn, e), xn, __LINE__);
    check(Interval::make_intersection(xn, n), n, __LINE__);
    check(Interval::make_intersection(n, xp), n, __LINE__);
    check(Interval::make_intersection(xp, xp), xp, __LINE__);

    check(Interval::make_union({3, Interval::pos_inf}, {5, Interval::pos_inf}), {3, Interval::pos_inf}, __LINE__);
    check(Interval::make_intersection({3, Interval::pos_inf}, {5, Interval::pos_inf}), {5, Interval::pos_inf}, __LINE__);

    check(Interval::make_union({Interval::neg_inf, 3}, {Interval::neg_inf, 5}), {Interval::neg_inf, 5}, __LINE__);
    check(Interval::make_intersection({Interval::neg_inf, 3}, {Interval::neg_inf, 5}), {Interval::neg_inf, 3}, __LINE__);

    check(Interval::make_union({3, 4}, {9, 10}), {3, 10}, __LINE__);
    check(Interval::make_intersection({3, 4}, {9, 10}), {9, 4}, __LINE__);

    check(Interval::make_union({3, 9}, {4, 10}), {3, 10}, __LINE__);
    check(Interval::make_intersection({3, 9}, {4, 10}), {4, 9}, __LINE__);

    std::cout << "Interval test passed" << std::endl;
}

}
}
<commit_msg>Fix possible infinite loop<commit_after>#include "Interval.h"
#include "IROperator.h"
#include "IREquality.h"

namespace Halide {
namespace Internal {

// This is called repeatedly by bounds inference and the solver to
// build large expressions, so we want to simplify eagerly to avoid
// monster expressions.
Expr Interval::make_max(Expr a, Expr b) {
    if (a.same_as(b)) return a;

    // Deal with infinities
    if (a.same_as(Interval::pos_inf)) return a;
    if (b.same_as(Interval::pos_inf)) return b;
    if (a.same_as(Interval::neg_inf)) return b;
    if (b.same_as(Interval::neg_inf)) return a;

    // Constant fold
    const int64_t *ia = as_const_int(a);
    const int64_t *ib = as_const_int(b);
    const uint64_t *ua = as_const_uint(a);
    const uint64_t *ub = as_const_uint(b);
    const double *fa = as_const_float(a);
    const double *fb = as_const_float(b);
    if (ia && ib) return (*ia > *ib) ? a : b;
    if (ua && ub) return (*ua > *ub) ? a : b;
    if (fa && fb) return (*fa > *fb) ? a : b;

    // Balance trees to the left, with constants pushed rightwards
    const Max *ma = a.as<Max>();
    const Max *mb = b.as<Max>();
    if (mb && !ma && !(is_const(mb->a) && is_const(mb->b))) {
        std::swap(ma, mb);
        std::swap(a, b);
    }
    if (ma && is_const(ma->b) && is_const(b)) {
        return Interval::make_max(ma->a, Interval::make_max(ma->b, b));
    }
    if (ma && (ma->a.same_as(b) || ma->b.same_as(b))) {
        // b is already represented in a
        return a;
    }

    return Max::make(a, b);
}

Expr Interval::make_min(Expr a, Expr b) {
    if (a.same_as(b)) return a;

    // Deal with infinities
    if (a.same_as(Interval::pos_inf)) return b;
    if (b.same_as(Interval::pos_inf)) return a;
    if (a.same_as(Interval::neg_inf)) return a;
    if (b.same_as(Interval::neg_inf)) return b;

    // Constant fold
    const int64_t *ia = as_const_int(a);
    const int64_t *ib = as_const_int(b);
    const uint64_t *ua = as_const_uint(a);
    const uint64_t *ub = as_const_uint(b);
    const double *fa = as_const_float(a);
    const double *fb = as_const_float(b);
    if (ia && ib) return (*ia > *ib) ? b : a;
    if (ua && ub) return (*ua > *ub) ? b : a;
    if (fa && fb) return (*fa > *fb) ? b : a;

    // Balance trees to the left, with constants pushed rightwards
    const Min *ma = a.as<Min>();
    const Min *mb = b.as<Min>();
    if (mb && !ma && !(is_const(mb->a) && is_const(mb->b))) {
        std::swap(ma, mb);
        std::swap(a, b);
    }
    if (ma && is_const(ma->b) && is_const(b)) {
        return Interval::make_min(ma->a, Interval::make_min(ma->b, b));
    }
    if (ma && (ma->a.same_as(b) || ma->b.same_as(b))) {
        // b is already represented in a
        return a;
    }

    return Min::make(a, b);
}

void Interval::include(const Interval &i) {
    max = Interval::make_max(max, i.max);
    min = Interval::make_min(min, i.min);
}

void Interval::include(Expr e) {
    max = Interval::make_max(max, e);
    min = Interval::make_min(min, e);
}

Interval Interval::make_union(const Interval &a, const Interval &b) {
    Interval result = a;
    result.include(b);
    return result;
}

Interval Interval::make_intersection(const Interval &a, const Interval &b) {
    return Interval(Interval::make_max(a.min, b.min),
                    Interval::make_min(a.max, b.max));
}

// Use Handle types for positive and negative infinity, to prevent
// accidentally doing arithmetic on them.
Expr Interval::pos_inf = Variable::make(Handle(), "pos_inf");
Expr Interval::neg_inf = Variable::make(Handle(), "neg_inf");

namespace {
void check(Interval result, Interval expected, int line) {
    internal_assert(equal(result.min, expected.min) &&
                    equal(result.max, expected.max))
        << "Interval test on line " << line << " failed\n"
        << "  Expected [" << expected.min << ", " << expected.max << "]\n"
        << "  Got      [" << result.min << ", " << result.max << "]\n";
}
}

void interval_test() {
    Interval e = Interval::everything();
    Interval n = Interval::nothing();
    Expr x = Variable::make(Int(32), "x");
    Interval xp{x, Interval::pos_inf};
    Interval xn{Interval::neg_inf, x};
    Interval xx{x, x};

    internal_assert(e.is_everything());
    internal_assert(!e.has_upper_bound());
    internal_assert(!e.has_lower_bound());
    internal_assert(!e.is_empty());
    internal_assert(!e.is_bounded());
    internal_assert(!e.is_single_point());

    internal_assert(!n.is_everything());
    internal_assert(!n.has_upper_bound());
    internal_assert(!n.has_lower_bound());
    internal_assert(n.is_empty());
    internal_assert(!n.is_bounded());
    internal_assert(!n.is_single_point());

    internal_assert(!xp.is_everything());
    internal_assert(!xp.has_upper_bound());
    internal_assert(xp.has_lower_bound());
    internal_assert(!xp.is_empty());
    internal_assert(!xp.is_bounded());
    internal_assert(!xp.is_single_point());

    internal_assert(!xn.is_everything());
    internal_assert(xn.has_upper_bound());
    internal_assert(!xn.has_lower_bound());
    internal_assert(!xn.is_empty());
    internal_assert(!xn.is_bounded());
    internal_assert(!xn.is_single_point());

    internal_assert(!xx.is_everything());
    internal_assert(xx.has_upper_bound());
    internal_assert(xx.has_lower_bound());
    internal_assert(!xx.is_empty());
    internal_assert(xx.is_bounded());
    internal_assert(xx.is_single_point());

    check(Interval::make_union(xp, xn), e, __LINE__);
    check(Interval::make_union(e, xn), e, __LINE__);
    check(Interval::make_union(xn, e), e, __LINE__);
    check(Interval::make_union(xn, n), xn, __LINE__);
    check(Interval::make_union(n, xp), xp, __LINE__);
    check(Interval::make_union(xp, xp), xp, __LINE__);

    check(Interval::make_intersection(xp, xn), Interval::single_point(x), __LINE__);
    check(Interval::make_intersection(e, xn), xn, __LINE__);
    check(Interval::make_intersection(xn, e), xn, __LINE__);
    check(Interval::make_intersection(xn, n), n, __LINE__);
    check(Interval::make_intersection(n, xp), n, __LINE__);
    check(Interval::make_intersection(xp, xp), xp, __LINE__);

    check(Interval::make_union({3, Interval::pos_inf}, {5, Interval::pos_inf}), {3, Interval::pos_inf}, __LINE__);
    check(Interval::make_intersection({3, Interval::pos_inf}, {5, Interval::pos_inf}), {5, Interval::pos_inf}, __LINE__);

    check(Interval::make_union({Interval::neg_inf, 3}, {Interval::neg_inf, 5}), {Interval::neg_inf, 5}, __LINE__);
    check(Interval::make_intersection({Interval::neg_inf, 3}, {Interval::neg_inf, 5}), {Interval::neg_inf, 3}, __LINE__);

    check(Interval::make_union({3, 4}, {9, 10}), {3, 10}, __LINE__);
    check(Interval::make_intersection({3, 4}, {9, 10}), {9, 4}, __LINE__);

    check(Interval::make_union({3, 9}, {4, 10}), {3, 10}, __LINE__);
    check(Interval::make_intersection({3, 9}, {4, 10}), {4, 9}, __LINE__);

    std::cout << "Interval test passed" << std::endl;
}

}
}
<|endoftext|>


<commit_before>/*
 * Distributed under the OSI-approved Apache License, Version 2.0.  See
 * accompanying file Copyright.txt for details.
 *
 * IO_h5mixer.cpp
 *
 *  Created on: Feb 2017
 *      Author: Norbert Podhorszki
 */

#include "IO.h"

#include <string>

#include <adios2.h>

#define str_helper(X) #X
#define str(X) str_helper(X)
//#ifndef DEFAULT_CONFIG
//#define DEFAULT_CONFIG config.xml
//#endif
#define DEFAULT_CONFIG mix.xml
#define DEFAULT_CONFIG_STR str(DEFAULT_CONFIG)

static int rank_saved;
adios2::ADIOS *ad = nullptr;
// std::shared_ptr<adios2::Engine> h5mixerWriter;
adios2::Engine h5mixerWriter;
adios2::Variable<double> varT;
adios2::Variable<unsigned int> varGndx;

IO::IO(const Settings &s, MPI_Comm comm)
{
    rank_saved = s.rank;

    m_outputfilename = MakeFilename(s.outputfile, ".h5");

    /*ad = new adios2::ADIOS(std::string(DEFAULT_CONFIG_STR), comm);
     */
    ad = new adios2::ADIOS(comm);

    // Define method for engine creation

    adios2::IO h5io = ad->DeclareIO("writer");
    if (!h5io.InConfigFile())
    {
        // if not defined by user, we can change the default settings
        // BPFile is the default engine

        // Allow an extra thread for data processing
        // ISO-POSIX file is the default transport
        // Passing parameters to the transport
        h5io.SetEngine("HDFMixer");
    }

    varGndx = h5io.DefineVariable<unsigned int>("gndx");
    h5io.DefineVariable<unsigned int>("gndy");

    // define T as 2D global array
    varT = h5io.DefineVariable<double>(
        "T",
        // Global dimensions
        {s.gndx, s.gndy},
        // starting offset of the local array in the global space
        {s.offsx, s.offsy},
        // local size, could be defined later using SetSelection()
        {s.ndx, s.ndy});

    // add transform to variable
    // adios2::Transform tr = adios2::transform::BZIP2( );
    // varT.AddTransform( tr, "" );
    // varT.AddTransform( tr,"accuracy=0.001" );  // for ZFP

    h5mixerWriter = h5io.Open(m_outputfilename, adios2::Mode::Write, comm);

    if (!h5mixerWriter)
    {
        throw std::ios_base::failure(
            "ERROR: failed to open ADIOS h5mixerWriter\n");
    }
}

IO::~IO()
{
    h5mixerWriter.Close();
    delete ad;
}

void IO::write(int step, const HeatTransfer &ht, const Settings &s,
               MPI_Comm comm)
{

    h5mixerWriter.BeginStep();
    /* This selection is redundant and not required, since we defined
     * the selection already in DefineVariable(). It is here just as an example.
     */
    // Make a selection to describe the local dimensions of the variable we
    // write and its offsets in the global spaces. This could have been done in
    // adios.DefineVariable()
    varT.SetSelection(
        adios2::Box<adios2::Dims>({s.offsx, s.offsy}, {s.ndx, s.ndy}));

    /* Select the area that we want to write from the data pointer we pass to
         the
         writer.
         Think HDF5 memspace, just not hyperslabs, only a bounding box
       selection. Engine will copy this bounding box from the data pointer into
       the output buffer. Size of the bounding box should match the "space"
       selection which was given above. Default memspace is always the full
       selection.
    */
    // varT.SetMemorySelection(adios2::Box<adios2::Dims>({1, 1}, {s.ndx,
    // s.ndy}));

    h5mixerWriter.Put<unsigned int>(varGndx, s.gndx);
    h5mixerWriter.Put<unsigned int>("gndy", s.gndy);
    h5mixerWriter.Put<double>(varT, ht.data_noghost().data());

    h5mixerWriter.EndStep();

#ifdef NEVER
#if 1

    /* This selection is redundant and not required, since we defined
     * the selection already in DefineVariable(). It is here just as an example.
     */
    // Make a selection to describe the local dimensions of the variable we
    // write and its offsets in the global spaces. This could have been done in
    // adios.DefineVariable()
    adios2::SelectionBoundingBox sel({s.offsx, s.offsy}, {s.ndx, s.ndy});
    varT->SetSelection(sel);

    /* Select the area that we want to write from the data pointer we pass to
       the
       writer.
       Think HDF5 memspace, just not hyperslabs, only a bounding box selection.
       Engine will copy this bounding box from the data pointer into the output
       buffer.
       Size of the bounding box should match the "space" selection which was
       given
       above.
       Default memspace is always the full selection.
    */
    adios2::SelectionBoundingBox memspace =
        adios2::SelectionBoundingBox({1, 1}, {s.ndx, s.ndy});
    varT->SetMemorySelection(memspace);

    h5mixerWriter->Write<unsigned int>(*varGndx, s.gndx);
    h5mixerWriter->Write<unsigned int>("gndy", s.gndy);
    h5mixerWriter->Write<double>(*varT, ht.data_noghost().data());
    h5mixerWriter->Advance();

#else
    h5mixerWriter->Write<double>(*varT, ht.data_noghost().data());
    h5mixerWriter->Advance();
#endif
#endif
}
<commit_msg>examples: Remove unused variable from IO_h5mixer<commit_after>/*
 * Distributed under the OSI-approved Apache License, Version 2.0.  See
 * accompanying file Copyright.txt for details.
 *
 * IO_h5mixer.cpp
 *
 *  Created on: Feb 2017
 *      Author: Norbert Podhorszki
 */

#include "IO.h"

#include <string>

#include <adios2.h>

#define str_helper(X) #X
#define str(X) str_helper(X)
//#ifndef DEFAULT_CONFIG
//#define DEFAULT_CONFIG config.xml
//#endif
#define DEFAULT_CONFIG mix.xml
#define DEFAULT_CONFIG_STR str(DEFAULT_CONFIG)

adios2::ADIOS *ad = nullptr;
// std::shared_ptr<adios2::Engine> h5mixerWriter;
adios2::Engine h5mixerWriter;
adios2::Variable<double> varT;
adios2::Variable<unsigned int> varGndx;

IO::IO(const Settings &s, MPI_Comm comm)
{
    m_outputfilename = MakeFilename(s.outputfile, ".h5");

    /*ad = new adios2::ADIOS(std::string(DEFAULT_CONFIG_STR), comm);
     */
    ad = new adios2::ADIOS(comm);

    // Define method for engine creation

    adios2::IO h5io = ad->DeclareIO("writer");
    if (!h5io.InConfigFile())
    {
        // if not defined by user, we can change the default settings
        // BPFile is the default engine

        // Allow an extra thread for data processing
        // ISO-POSIX file is the default transport
        // Passing parameters to the transport
        h5io.SetEngine("HDFMixer");
    }

    varGndx = h5io.DefineVariable<unsigned int>("gndx");
    h5io.DefineVariable<unsigned int>("gndy");

    // define T as 2D global array
    varT = h5io.DefineVariable<double>(
        "T",
        // Global dimensions
        {s.gndx, s.gndy},
        // starting offset of the local array in the global space
        {s.offsx, s.offsy},
        // local size, could be defined later using SetSelection()
        {s.ndx, s.ndy});

    // add transform to variable
    // adios2::Transform tr = adios2::transform::BZIP2( );
    // varT.AddTransform( tr, "" );
    // varT.AddTransform( tr,"accuracy=0.001" );  // for ZFP

    h5mixerWriter = h5io.Open(m_outputfilename, adios2::Mode::Write, comm);

    if (!h5mixerWriter)
    {
        throw std::ios_base::failure(
            "ERROR: failed to open ADIOS h5mixerWriter\n");
    }
}

IO::~IO()
{
    h5mixerWriter.Close();
    delete ad;
}

void IO::write(int step, const HeatTransfer &ht, const Settings &s,
               MPI_Comm comm)
{

    h5mixerWriter.BeginStep();
    /* This selection is redundant and not required, since we defined
     * the selection already in DefineVariable(). It is here just as an example.
     */
    // Make a selection to describe the local dimensions of the variable we
    // write and its offsets in the global spaces. This could have been done in
    // adios.DefineVariable()
    varT.SetSelection(
        adios2::Box<adios2::Dims>({s.offsx, s.offsy}, {s.ndx, s.ndy}));

    /* Select the area that we want to write from the data pointer we pass to
         the
         writer.
         Think HDF5 memspace, just not hyperslabs, only a bounding box
       selection. Engine will copy this bounding box from the data pointer into
       the output buffer. Size of the bounding box should match the "space"
       selection which was given above. Default memspace is always the full
       selection.
    */
    // varT.SetMemorySelection(adios2::Box<adios2::Dims>({1, 1}, {s.ndx,
    // s.ndy}));

    h5mixerWriter.Put<unsigned int>(varGndx, s.gndx);
    h5mixerWriter.Put<unsigned int>("gndy", s.gndy);
    h5mixerWriter.Put<double>(varT, ht.data_noghost().data());

    h5mixerWriter.EndStep();

#ifdef NEVER
#if 1

    /* This selection is redundant and not required, since we defined
     * the selection already in DefineVariable(). It is here just as an example.
     */
    // Make a selection to describe the local dimensions of the variable we
    // write and its offsets in the global spaces. This could have been done in
    // adios.DefineVariable()
    adios2::SelectionBoundingBox sel({s.offsx, s.offsy}, {s.ndx, s.ndy});
    varT->SetSelection(sel);

    /* Select the area that we want to write from the data pointer we pass to
       the
       writer.
       Think HDF5 memspace, just not hyperslabs, only a bounding box selection.
       Engine will copy this bounding box from the data pointer into the output
       buffer.
       Size of the bounding box should match the "space" selection which was
       given
       above.
       Default memspace is always the full selection.
    */
    adios2::SelectionBoundingBox memspace =
        adios2::SelectionBoundingBox({1, 1}, {s.ndx, s.ndy});
    varT->SetMemorySelection(memspace);

    h5mixerWriter->Write<unsigned int>(*varGndx, s.gndx);
    h5mixerWriter->Write<unsigned int>("gndy", s.gndy);
    h5mixerWriter->Write<double>(*varT, ht.data_noghost().data());
    h5mixerWriter->Advance();

#else
    h5mixerWriter->Write<double>(*varT, ht.data_noghost().data());
    h5mixerWriter->Advance();
#endif
#endif
}
<|endoftext|>


<commit_before>#include "Renderer.hpp"

#include <GL/glew.h>
#include "RenderProgram/StaticRenderProgram.hpp"
#include "RenderProgram/SkinRenderProgram.hpp"
#include "RenderSurface.hpp"
#include "PostProcessing/PostProcessing.hpp"
#include "PostProcessing/FXAAFilter.hpp"
#include "Texture/Texture2D.hpp"
#include "Shader/Shader.hpp"
#include "Shader/ShaderProgram.hpp"
#include "EditorEntity.vert.hpp"
#include "EditorEntity.geom.hpp"
#include "EditorEntity.frag.hpp"
#include "Geometry/Rectangle.hpp"
#include "Buffer/FrameBuffer.hpp"
#include "Buffer/StorageBuffer.hpp"

using namespace Video;

Renderer::Renderer() {
    rectangle = new Geometry::Rectangle();
    staticRenderProgram = new StaticRenderProgram();

    postProcessing = new PostProcessing(rectangle);

    fxaaFilter = new FXAAFilter();

    lightCount = 0;
    lightBuffer = new StorageBuffer(sizeof(Video::Light), GL_DYNAMIC_DRAW);

    // Icon rendering.
    Shader* iconVertexShader = new Shader(EDITORENTITY_VERT, EDITORENTITY_VERT_LENGTH, GL_VERTEX_SHADER);
    Shader* iconGeometryShader = new Shader(EDITORENTITY_GEOM, EDITORENTITY_GEOM_LENGTH, GL_GEOMETRY_SHADER);
    Shader* iconFragmentShader = new Shader(EDITORENTITY_FRAG, EDITORENTITY_FRAG_LENGTH, GL_FRAGMENT_SHADER);
    iconShaderProgram = new ShaderProgram({ iconVertexShader, iconGeometryShader, iconFragmentShader });
    delete iconVertexShader;
    delete iconGeometryShader;
    delete iconFragmentShader;

    // Create icon geometry.
    float vertex;

    glBindVertexArray(0);
    glGenBuffers(1, &vertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, 1 * sizeof(float), &vertex, GL_STATIC_DRAW);

    glGenVertexArrays(1, &vertexArray);
    glBindVertexArray(vertexArray);

    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);

    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, sizeof(float), nullptr);

    glBindVertexArray(0);
}

Renderer::~Renderer() {
    delete rectangle;
    delete staticRenderProgram;

    delete postProcessing;
    delete fxaaFilter;

    delete lightBuffer;

    // Icon rendering.
    delete iconShaderProgram;
    glDeleteBuffers(1, &vertexBuffer);
    glDeleteVertexArrays(1, &vertexArray);
}

void Renderer::PrepareStaticMeshDepthRendering(const glm::mat4& viewMatrix, const glm::mat4& projectionMatrix) {
    staticRenderProgram->PreDepthRender(viewMatrix, projectionMatrix);
}

void Renderer::DepthRenderStaticMesh(Geometry::Geometry3D* geometry, const glm::mat4& viewMatrix, const glm::mat4& projectionMatrix, const glm::mat4& modelMatrix) {
    staticRenderProgram->DepthRender(geometry, viewMatrix, projectionMatrix, modelMatrix);
}

void Renderer::StartRendering(RenderSurface* renderSurface) {
    renderSurface->Clear();
    glViewport(0, 0, static_cast<GLsizei>(renderSurface->GetSize().x), static_cast<GLsizei>(renderSurface->GetSize().y));
}

void Renderer::SetLights(const std::vector<Video::Light>& lights) {
    lightCount = lights.size();

    // Skip if no lights.
    if (lightCount == 0) return;

    // Resize light buffer if necessary.
    unsigned int byteSize = sizeof(Video::Light) * lights.size();
    if (lightBuffer->GetSize() < byteSize) {
        delete lightBuffer;
        lightBuffer = new StorageBuffer(byteSize, GL_DYNAMIC_DRAW);
    }

    // Update light buffer.
    lightBuffer->Bind();
    lightBuffer->Write((void*)lights.data(), 0, byteSize);
    lightBuffer->Unbind();
}

void Renderer::PrepareStaticMeshRendering(const glm::mat4& viewMatrix, const glm::mat4& projectionMatrix) {
    staticRenderProgram->PreRender(viewMatrix, projectionMatrix, lightBuffer, lightCount);
}

void Renderer::RenderStaticMesh(Geometry::Geometry3D* geometry, const Texture2D* albedo, const Texture2D* normal, const Texture2D* metallic, const Texture2D* roughness, const glm::mat4 modelMatrix, bool isSelected) {
    staticRenderProgram->Render(geometry, albedo, normal, metallic, roughness, modelMatrix, isSelected);
}

void Renderer::AntiAlias(RenderSurface* renderSurface) {
    fxaaFilter->SetScreenSize(renderSurface->GetSize());
    postProcessing->ApplyFilter(renderSurface, fxaaFilter);
}

void Renderer::Present(RenderSurface* renderSurface) {
    renderSurface->GetColorFrameBuffer()->BindRead();
    glReadBuffer(GL_COLOR_ATTACHMENT0);
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
    const glm::vec2 size = renderSurface->GetSize();
    glBlitFramebuffer(0, 0, size.x, size.y, 0, 0, size.x, size.y, GL_COLOR_BUFFER_BIT, GL_NEAREST);
    renderSurface->GetColorFrameBuffer()->Unbind();
}

void Renderer::PrepareRenderingIcons(const glm::mat4& viewProjectionMatrix, const glm::vec3& cameraPosition, const glm::vec3& cameraUp) {
    iconShaderProgram->Use();
    glBindVertexArray(vertexArray);
    glDepthMask(GL_FALSE);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE);

    // Set camera uniforms.
    glUniformMatrix4fv(iconShaderProgram->GetUniformLocation("viewProjectionMatrix"), 1, GL_FALSE, &viewProjectionMatrix[0][0]);
    glUniform3fv(iconShaderProgram->GetUniformLocation("cameraPosition"), 1, &cameraPosition[0]);
    glUniform3fv(iconShaderProgram->GetUniformLocation("cameraUp"), 1, &cameraUp[0]);
    glUniform1i(iconShaderProgram->GetUniformLocation("baseImage"), 0);

    glActiveTexture(GL_TEXTURE0);
}

void Renderer::RenderIcon(const glm::vec3& position, const Texture2D* icon) {
    if (currentIcon != icon) {
        currentIcon = icon;
        glBindTexture(GL_TEXTURE_2D, icon->GetTextureID());
    }

    glUniform3fv(iconShaderProgram->GetUniformLocation("position"), 1, &position[0]);
    glDrawArrays(GL_POINTS, 0, 1);
}

void Renderer::StopRenderingIcons() {
    glDepthMask(GL_TRUE);
    glDisable(GL_BLEND);
}

<commit_msg>Blit depth buffer<commit_after>#include "Renderer.hpp"

#include <GL/glew.h>
#include "RenderProgram/StaticRenderProgram.hpp"
#include "RenderProgram/SkinRenderProgram.hpp"
#include "RenderSurface.hpp"
#include "PostProcessing/PostProcessing.hpp"
#include "PostProcessing/FXAAFilter.hpp"
#include "Texture/Texture2D.hpp"
#include "Shader/Shader.hpp"
#include "Shader/ShaderProgram.hpp"
#include "EditorEntity.vert.hpp"
#include "EditorEntity.geom.hpp"
#include "EditorEntity.frag.hpp"
#include "Geometry/Rectangle.hpp"
#include "Buffer/FrameBuffer.hpp"
#include "Buffer/StorageBuffer.hpp"

using namespace Video;

Renderer::Renderer() {
    rectangle = new Geometry::Rectangle();
    staticRenderProgram = new StaticRenderProgram();

    postProcessing = new PostProcessing(rectangle);

    fxaaFilter = new FXAAFilter();

    lightCount = 0;
    lightBuffer = new StorageBuffer(sizeof(Video::Light), GL_DYNAMIC_DRAW);

    // Icon rendering.
    Shader* iconVertexShader = new Shader(EDITORENTITY_VERT, EDITORENTITY_VERT_LENGTH, GL_VERTEX_SHADER);
    Shader* iconGeometryShader = new Shader(EDITORENTITY_GEOM, EDITORENTITY_GEOM_LENGTH, GL_GEOMETRY_SHADER);
    Shader* iconFragmentShader = new Shader(EDITORENTITY_FRAG, EDITORENTITY_FRAG_LENGTH, GL_FRAGMENT_SHADER);
    iconShaderProgram = new ShaderProgram({ iconVertexShader, iconGeometryShader, iconFragmentShader });
    delete iconVertexShader;
    delete iconGeometryShader;
    delete iconFragmentShader;

    // Create icon geometry.
    float vertex;

    glBindVertexArray(0);
    glGenBuffers(1, &vertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, 1 * sizeof(float), &vertex, GL_STATIC_DRAW);

    glGenVertexArrays(1, &vertexArray);
    glBindVertexArray(vertexArray);

    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);

    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, sizeof(float), nullptr);

    glBindVertexArray(0);
}

Renderer::~Renderer() {
    delete rectangle;
    delete staticRenderProgram;

    delete postProcessing;
    delete fxaaFilter;

    delete lightBuffer;

    // Icon rendering.
    delete iconShaderProgram;
    glDeleteBuffers(1, &vertexBuffer);
    glDeleteVertexArrays(1, &vertexArray);
}

void Renderer::PrepareStaticMeshDepthRendering(const glm::mat4& viewMatrix, const glm::mat4& projectionMatrix) {
    staticRenderProgram->PreDepthRender(viewMatrix, projectionMatrix);
}

void Renderer::DepthRenderStaticMesh(Geometry::Geometry3D* geometry, const glm::mat4& viewMatrix, const glm::mat4& projectionMatrix, const glm::mat4& modelMatrix) {
    staticRenderProgram->DepthRender(geometry, viewMatrix, projectionMatrix, modelMatrix);
}

void Renderer::StartRendering(RenderSurface* renderSurface) {
    renderSurface->Clear();
    glViewport(0, 0, static_cast<GLsizei>(renderSurface->GetSize().x), static_cast<GLsizei>(renderSurface->GetSize().y));
}

void Renderer::SetLights(const std::vector<Video::Light>& lights) {
    lightCount = lights.size();

    // Skip if no lights.
    if (lightCount == 0) return;

    // Resize light buffer if necessary.
    unsigned int byteSize = sizeof(Video::Light) * lights.size();
    if (lightBuffer->GetSize() < byteSize) {
        delete lightBuffer;
        lightBuffer = new StorageBuffer(byteSize, GL_DYNAMIC_DRAW);
    }

    // Update light buffer.
    lightBuffer->Bind();
    lightBuffer->Write((void*)lights.data(), 0, byteSize);
    lightBuffer->Unbind();
}

void Renderer::PrepareStaticMeshRendering(const glm::mat4& viewMatrix, const glm::mat4& projectionMatrix) {
    staticRenderProgram->PreRender(viewMatrix, projectionMatrix, lightBuffer, lightCount);
}

void Renderer::RenderStaticMesh(Geometry::Geometry3D* geometry, const Texture2D* albedo, const Texture2D* normal, const Texture2D* metallic, const Texture2D* roughness, const glm::mat4 modelMatrix, bool isSelected) {
    staticRenderProgram->Render(geometry, albedo, normal, metallic, roughness, modelMatrix, isSelected);
}

void Renderer::AntiAlias(RenderSurface* renderSurface) {
    fxaaFilter->SetScreenSize(renderSurface->GetSize());
    postProcessing->ApplyFilter(renderSurface, fxaaFilter);
}

void Renderer::Present(RenderSurface* renderSurface) {
    const glm::vec2 size = renderSurface->GetSize();

    /// @todo See if doing this with a fullscreen quad would be faster.
    /// With a fullscreen this would be one command (copying both color and depth) instead of two.
    /// Additionally, online sources seem to indicate fullscreen quads are slightly faster than blitting.

    // Copy color buffer.
    renderSurface->GetColorFrameBuffer()->BindRead();
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
    glBlitFramebuffer(0, 0, size.x, size.y, 0, 0, size.x, size.y, GL_COLOR_BUFFER_BIT, GL_NEAREST);
    renderSurface->GetColorFrameBuffer()->Unbind();

    // Copy depth buffer.
    renderSurface->GetDepthFrameBuffer()->BindRead();
    glBlitFramebuffer(0, 0, size.x, size.y, 0, 0, size.x, size.y, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
    renderSurface->GetDepthFrameBuffer()->Unbind();
}

void Renderer::PrepareRenderingIcons(const glm::mat4& viewProjectionMatrix, const glm::vec3& cameraPosition, const glm::vec3& cameraUp) {
    iconShaderProgram->Use();
    glBindVertexArray(vertexArray);
    glDepthMask(GL_FALSE);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE);

    // Set camera uniforms.
    glUniformMatrix4fv(iconShaderProgram->GetUniformLocation("viewProjectionMatrix"), 1, GL_FALSE, &viewProjectionMatrix[0][0]);
    glUniform3fv(iconShaderProgram->GetUniformLocation("cameraPosition"), 1, &cameraPosition[0]);
    glUniform3fv(iconShaderProgram->GetUniformLocation("cameraUp"), 1, &cameraUp[0]);
    glUniform1i(iconShaderProgram->GetUniformLocation("baseImage"), 0);

    glActiveTexture(GL_TEXTURE0);
}

void Renderer::RenderIcon(const glm::vec3& position, const Texture2D* icon) {
    if (currentIcon != icon) {
        currentIcon = icon;
        glBindTexture(GL_TEXTURE_2D, icon->GetTextureID());
    }

    glUniform3fv(iconShaderProgram->GetUniformLocation("position"), 1, &position[0]);
    glDrawArrays(GL_POINTS, 0, 1);
}

void Renderer::StopRenderingIcons() {
    glDepthMask(GL_TRUE);
    glDisable(GL_BLEND);
}

<|endoftext|>