<commit_before>/*
 * Copyright (c) 2011-2012 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2002-2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Ron Dreslinski
 *          Andreas Hansson
 *          William Wang
 */

/**
 * @file
 * Port Object Declaration.
 */

#ifndef __MEM_PORT_HH__
#define __MEM_PORT_HH__

#include <list>

#include "base/addr_range.hh"
#include "mem/packet.hh"

/**
 * This typedef is used to clean up getAddrRanges(). It's declared
 * outside the Port object since it's also used by some mem objects.
 * Eventually we should move this typedef to wherever Addr is
 * defined.
 */

typedef std::list<AddrRange> AddrRangeList;
typedef std::list<AddrRange>::iterator AddrRangeIter;
typedef std::list<AddrRange>::const_iterator AddrRangeConstIter;

class MemObject;

/**
 * Ports are used to interface memory objects to each other. A port is
 * either a master or a slave and the connected peer is always of the
 * opposite role. Each port has a name, an owner, and an identifier.
 */
class Port
{

  private:

    /** Descriptive name (for DPRINTF output) */
    std::string portName;

  protected:

    /**
     * A numeric identifier to distinguish ports in a vector, and set
     * to InvalidPortID in case this port is not part of a vector.
     */
    const PortID id;

    /** A reference to the MemObject that owns this port. */
    MemObject& owner;

    /**
     * Abstract base class for ports
     *
     * @param _name Port name including the owners name
     * @param _owner The MemObject that is the structural owner of this port
     * @param _id A port identifier for vector ports
     */
    Port(const std::string& _name, MemObject& _owner, PortID _id);

    /**
     * Virtual destructor due to inheritance.
     */
    virtual ~Port();

  public:

    /** Return port name (for DPRINTF). */
    const std::string name() const { return portName; }

    /** Get the port id. */
    PortID getId() const { return id; }

};

/** Forward declaration */
class BaseSlavePort;

/**
 * A BaseMasterPort is a protocol-agnostic master port, responsible
 * only for the structural connection to a slave port. The final
 * master port that inherits from the base class must override the
 * bind member function for the specific slave port class.
 */
class BaseMasterPort : public Port
{

  protected:

    BaseSlavePort* _baseSlavePort;

    BaseMasterPort(const std::string& name, MemObject* owner,
                   PortID id = InvalidPortID);
    virtual ~BaseMasterPort();

  public:

    virtual void bind(BaseSlavePort& slave_port) = 0;
    virtual void unbind() = 0;
    BaseSlavePort& getSlavePort() const;
    bool isConnected() const;

};

/**
 * A BaseSlavePort is a protocol-agnostic slave port, responsible
 * only for the structural connection to a master port.
 */
class BaseSlavePort : public Port
{

  protected:

    BaseMasterPort* _baseMasterPort;

    BaseSlavePort(const std::string& name, MemObject* owner,
                  PortID id = InvalidPortID);
    virtual ~BaseSlavePort();

  public:

    BaseMasterPort& getMasterPort() const;
    bool isConnected() const;

};

/** Forward declaration */
class SlavePort;

/**
 * A MasterPort is a specialisation of a BaseMasterPort, which
 * implements the default protocol for the three different level of
 * transport functions. In addition to the basic functionality of
 * sending packets, it also has functions to receive range changes or
 * determine if the port is snooping or not.
 */
class MasterPort : public BaseMasterPort
{

    friend class SlavePort;

  private:

    SlavePort* _slavePort;

  public:

    MasterPort(const std::string& name, MemObject* owner,
               PortID id = InvalidPortID);
    virtual ~MasterPort();

    /**
     * Bind this master port to a slave port. This also does the
     * mirror action and binds the slave port to the master port.
     */
    void bind(BaseSlavePort& slave_port);

    /**
     * Unbind this master port and the associated slave port.
     */
    void unbind();

    /**
     * Send an atomic request packet, where the data is moved and the
     * state is updated in zero time, without interleaving with other
     * memory accesses.
     *
     * @param pkt Packet to send.
     *
     * @return Estimated latency of access.
     */
    Tick sendAtomic(PacketPtr pkt);

    /**
     * Send a functional request packet, where the data is instantly
     * updated everywhere in the memory system, without affecting the
     * current state of any block or moving the block.
     *
     * @param pkt Packet to send.
     */
    void sendFunctional(PacketPtr pkt);

    /**
     * Attempt to send a timing request to the slave port by calling
     * its corresponding receive function. If the send does not
     * succeed, as indicated by the return value, then the sender must
     * wait for a recvRetry at which point it can re-issue a
     * sendTimingReq.
     *
     * @param pkt Packet to send.
     *
     * @return If the send was succesful or not.
    */
    bool sendTimingReq(PacketPtr pkt);

    /**
     * Attempt to send a timing snoop response packet to the slave
     * port by calling its corresponding receive function. If the send
     * does not succeed, as indicated by the return value, then the
     * sender must wait for a recvRetry at which point it can re-issue
     * a sendTimingSnoopResp.
     *
     * @param pkt Packet to send.
     */
    bool sendTimingSnoopResp(PacketPtr pkt);

    /**
     * Send a retry to the slave port that previously attempted a
     * sendTimingResp to this master port and failed.
     */
    void sendRetry();

    /**
     * Determine if this master port is snooping or not. The default
     * implementation returns false and thus tells the neighbour we
     * are not snooping. Any master port that wants to receive snoop
     * requests (e.g. a cache connected to a bus) has to override this
     * function.
     *
     * @return true if the port should be considered a snooper
     */
    virtual bool isSnooping() const { return false; }

    /**
     * Called by a peer port in order to determine the block size of
     * the owner of this port.
     */
    virtual unsigned deviceBlockSize() const { return 0; }

    /** Called by the associated device if it wishes to find out the blocksize
        of the device on attached to the peer port.
    */
    unsigned peerBlockSize() const;

    /**
     * Get the address ranges of the connected slave port.
     */
    AddrRangeList getAddrRanges() const;

    /** Inject a PrintReq for the given address to print the state of
     * that address throughout the memory system.  For debugging.
     */
    void printAddr(Addr a);

  protected:

    /**
     * Receive an atomic snoop request packet from the slave port.
     */
    virtual Tick recvAtomicSnoop(PacketPtr pkt)
    {
        panic("%s was not expecting an atomic snoop request\n", name());
        return 0;
    }

    /**
     * Receive a functional snoop request packet from the slave port.
     */
    virtual void recvFunctionalSnoop(PacketPtr pkt)
    {
        panic("%s was not expecting a functional snoop request\n", name());
    }

    /**
     * Receive a timing response from the slave port.
     */
    virtual bool recvTimingResp(PacketPtr pkt) = 0;

    /**
     * Receive a timing snoop request from the slave port.
     */
    virtual void recvTimingSnoopReq(PacketPtr pkt)
    {
        panic("%s was not expecting a timing snoop request\n", name());
    }

    /**
     * Called by the slave port if sendTimingReq or
     * sendTimingSnoopResp was called on this master port (causing
     * recvTimingReq and recvTimingSnoopResp to be called on the
     * slave port) and was unsuccesful.
     */
    virtual void recvRetry() = 0;

    /**
     * Called to receive an address range change from the peer slave
     * port. the default implementation ignored the change and does
     * nothing. Override this function in a derived class if the owner
     * needs to be aware of he laesddress ranges, e.g. in an
     * interconnect component like a bus.
     */
    virtual void recvRangeChange() { }
};

/**
 * A SlavePort is a specialisation of a port. In addition to the
 * basic functionality of sending packets to its master peer, it also
 * has functions specific to a slave, e.g. to send range changes
 * and get the address ranges that the port responds to.
 */
class SlavePort : public BaseSlavePort
{

    friend class MasterPort;

  private:

    MasterPort* _masterPort;

  public:

    SlavePort(const std::string& name, MemObject* owner,
              PortID id = InvalidPortID);
    virtual ~SlavePort();

    /**
     * Send an atomic snoop request packet, where the data is moved
     * and the state is updated in zero time, without interleaving
     * with other memory accesses.
     *
     * @param pkt Snoop packet to send.
     *
     * @return Estimated latency of access.
     */
    Tick sendAtomicSnoop(PacketPtr pkt);

    /**
     * Send a functional snoop request packet, where the data is
     * instantly updated everywhere in the memory system, without
     * affecting the current state of any block or moving the block.
     *
     * @param pkt Snoop packet to send.
     */
    void sendFunctionalSnoop(PacketPtr pkt);

    /**
     * Attempt to send a timing response to the master port by calling
     * its corresponding receive function. If the send does not
     * succeed, as indicated by the return value, then the sender must
     * wait for a recvRetry at which point it can re-issue a
     * sendTimingResp.
     *
     * @param pkt Packet to send.
     *
     * @return If the send was succesful or not.
    */
    bool sendTimingResp(PacketPtr pkt);

    /**
     * Attempt to send a timing snoop request packet to the master port
     * by calling its corresponding receive function. Snoop requests
     * always succeed and hence no return value is needed.
     *
     * @param pkt Packet to send.
     */
    void sendTimingSnoopReq(PacketPtr pkt);

    /**
     * Send a retry to the master port that previously attempted a
     * sendTimingReq or sendTimingSnoopResp to this slave port and
     * failed.
     */
    void sendRetry();

    /**
     * Called by a peer port in order to determine the block size of
     * the owner of this port.
     */
    virtual unsigned deviceBlockSize() const { return 0; }

    /** Called by the associated device if it wishes to find out the blocksize
        of the device on attached to the peer port.
    */
    unsigned peerBlockSize() const;

    /**
     * Find out if the peer master port is snooping or not.
     *
     * @return true if the peer master port is snooping
     */
    bool isSnooping() const { return _masterPort->isSnooping(); }

    /**
     * Called by the owner to send a range change
     */
    void sendRangeChange() const { _masterPort->recvRangeChange(); }

    /**
     * Get a list of the non-overlapping address ranges the owner is
     * responsible for. All slave ports must override this function
     * and return a populated list with at least one item.
     *
     * @return a list of ranges responded to
     */
    virtual AddrRangeList getAddrRanges() const = 0;

  protected:

    /**
     * Called by the master port to unbind. Should never be called
     * directly.
     */
    void unbind();

    /**
     * Called by the master port to bind. Should never be called
     * directly.
     */
    void bind(MasterPort& master_port);

    /**
     * Receive an atomic request packet from the master port.
     */
    virtual Tick recvAtomic(PacketPtr pkt) = 0;

    /**
     * Receive a functional request packet from the master port.
     */
    virtual void recvFunctional(PacketPtr pkt) = 0;

    /**
     * Receive a timing request from the master port.
     */
    virtual bool recvTimingReq(PacketPtr pkt) = 0;

    /**
     * Receive a timing snoop response from the master port.
     */
    virtual bool recvTimingSnoopResp(PacketPtr pkt)
    {
        panic("%s was not expecting a timing snoop response\n", name());
    }

    /**
     * Called by the master port if sendTimingResp was called on this
     * slave port (causing recvTimingResp to be called on the master
     * port) and was unsuccesful.
     */
    virtual void recvRetry() = 0;

};

#endif //__MEM_PORT_HH__
<commit_msg>mem: Fix typo in port comments<commit_after>/*
 * Copyright (c) 2011-2012 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2002-2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Ron Dreslinski
 *          Andreas Hansson
 *          William Wang
 */

/**
 * @file
 * Port Object Declaration.
 */

#ifndef __MEM_PORT_HH__
#define __MEM_PORT_HH__

#include <list>

#include "base/addr_range.hh"
#include "mem/packet.hh"

/**
 * This typedef is used to clean up getAddrRanges(). It's declared
 * outside the Port object since it's also used by some mem objects.
 * Eventually we should move this typedef to wherever Addr is
 * defined.
 */

typedef std::list<AddrRange> AddrRangeList;
typedef std::list<AddrRange>::iterator AddrRangeIter;
typedef std::list<AddrRange>::const_iterator AddrRangeConstIter;

class MemObject;

/**
 * Ports are used to interface memory objects to each other. A port is
 * either a master or a slave and the connected peer is always of the
 * opposite role. Each port has a name, an owner, and an identifier.
 */
class Port
{

  private:

    /** Descriptive name (for DPRINTF output) */
    std::string portName;

  protected:

    /**
     * A numeric identifier to distinguish ports in a vector, and set
     * to InvalidPortID in case this port is not part of a vector.
     */
    const PortID id;

    /** A reference to the MemObject that owns this port. */
    MemObject& owner;

    /**
     * Abstract base class for ports
     *
     * @param _name Port name including the owners name
     * @param _owner The MemObject that is the structural owner of this port
     * @param _id A port identifier for vector ports
     */
    Port(const std::string& _name, MemObject& _owner, PortID _id);

    /**
     * Virtual destructor due to inheritance.
     */
    virtual ~Port();

  public:

    /** Return port name (for DPRINTF). */
    const std::string name() const { return portName; }

    /** Get the port id. */
    PortID getId() const { return id; }

};

/** Forward declaration */
class BaseSlavePort;

/**
 * A BaseMasterPort is a protocol-agnostic master port, responsible
 * only for the structural connection to a slave port. The final
 * master port that inherits from the base class must override the
 * bind member function for the specific slave port class.
 */
class BaseMasterPort : public Port
{

  protected:

    BaseSlavePort* _baseSlavePort;

    BaseMasterPort(const std::string& name, MemObject* owner,
                   PortID id = InvalidPortID);
    virtual ~BaseMasterPort();

  public:

    virtual void bind(BaseSlavePort& slave_port) = 0;
    virtual void unbind() = 0;
    BaseSlavePort& getSlavePort() const;
    bool isConnected() const;

};

/**
 * A BaseSlavePort is a protocol-agnostic slave port, responsible
 * only for the structural connection to a master port.
 */
class BaseSlavePort : public Port
{

  protected:

    BaseMasterPort* _baseMasterPort;

    BaseSlavePort(const std::string& name, MemObject* owner,
                  PortID id = InvalidPortID);
    virtual ~BaseSlavePort();

  public:

    BaseMasterPort& getMasterPort() const;
    bool isConnected() const;

};

/** Forward declaration */
class SlavePort;

/**
 * A MasterPort is a specialisation of a BaseMasterPort, which
 * implements the default protocol for the three different level of
 * transport functions. In addition to the basic functionality of
 * sending packets, it also has functions to receive range changes or
 * determine if the port is snooping or not.
 */
class MasterPort : public BaseMasterPort
{

    friend class SlavePort;

  private:

    SlavePort* _slavePort;

  public:

    MasterPort(const std::string& name, MemObject* owner,
               PortID id = InvalidPortID);
    virtual ~MasterPort();

    /**
     * Bind this master port to a slave port. This also does the
     * mirror action and binds the slave port to the master port.
     */
    void bind(BaseSlavePort& slave_port);

    /**
     * Unbind this master port and the associated slave port.
     */
    void unbind();

    /**
     * Send an atomic request packet, where the data is moved and the
     * state is updated in zero time, without interleaving with other
     * memory accesses.
     *
     * @param pkt Packet to send.
     *
     * @return Estimated latency of access.
     */
    Tick sendAtomic(PacketPtr pkt);

    /**
     * Send a functional request packet, where the data is instantly
     * updated everywhere in the memory system, without affecting the
     * current state of any block or moving the block.
     *
     * @param pkt Packet to send.
     */
    void sendFunctional(PacketPtr pkt);

    /**
     * Attempt to send a timing request to the slave port by calling
     * its corresponding receive function. If the send does not
     * succeed, as indicated by the return value, then the sender must
     * wait for a recvRetry at which point it can re-issue a
     * sendTimingReq.
     *
     * @param pkt Packet to send.
     *
     * @return If the send was succesful or not.
    */
    bool sendTimingReq(PacketPtr pkt);

    /**
     * Attempt to send a timing snoop response packet to the slave
     * port by calling its corresponding receive function. If the send
     * does not succeed, as indicated by the return value, then the
     * sender must wait for a recvRetry at which point it can re-issue
     * a sendTimingSnoopResp.
     *
     * @param pkt Packet to send.
     */
    bool sendTimingSnoopResp(PacketPtr pkt);

    /**
     * Send a retry to the slave port that previously attempted a
     * sendTimingResp to this master port and failed.
     */
    void sendRetry();

    /**
     * Determine if this master port is snooping or not. The default
     * implementation returns false and thus tells the neighbour we
     * are not snooping. Any master port that wants to receive snoop
     * requests (e.g. a cache connected to a bus) has to override this
     * function.
     *
     * @return true if the port should be considered a snooper
     */
    virtual bool isSnooping() const { return false; }

    /**
     * Called by a peer port in order to determine the block size of
     * the owner of this port.
     */
    virtual unsigned deviceBlockSize() const { return 0; }

    /** Called by the associated device if it wishes to find out the blocksize
        of the device on attached to the peer port.
    */
    unsigned peerBlockSize() const;

    /**
     * Get the address ranges of the connected slave port.
     */
    AddrRangeList getAddrRanges() const;

    /** Inject a PrintReq for the given address to print the state of
     * that address throughout the memory system.  For debugging.
     */
    void printAddr(Addr a);

  protected:

    /**
     * Receive an atomic snoop request packet from the slave port.
     */
    virtual Tick recvAtomicSnoop(PacketPtr pkt)
    {
        panic("%s was not expecting an atomic snoop request\n", name());
        return 0;
    }

    /**
     * Receive a functional snoop request packet from the slave port.
     */
    virtual void recvFunctionalSnoop(PacketPtr pkt)
    {
        panic("%s was not expecting a functional snoop request\n", name());
    }

    /**
     * Receive a timing response from the slave port.
     */
    virtual bool recvTimingResp(PacketPtr pkt) = 0;

    /**
     * Receive a timing snoop request from the slave port.
     */
    virtual void recvTimingSnoopReq(PacketPtr pkt)
    {
        panic("%s was not expecting a timing snoop request\n", name());
    }

    /**
     * Called by the slave port if sendTimingReq or
     * sendTimingSnoopResp was called on this master port (causing
     * recvTimingReq and recvTimingSnoopResp to be called on the
     * slave port) and was unsuccesful.
     */
    virtual void recvRetry() = 0;

    /**
     * Called to receive an address range change from the peer slave
     * port. The default implementation ignores the change and does
     * nothing. Override this function in a derived class if the owner
     * needs to be aware of the address ranges, e.g. in an
     * interconnect component like a bus.
     */
    virtual void recvRangeChange() { }
};

/**
 * A SlavePort is a specialisation of a port. In addition to the
 * basic functionality of sending packets to its master peer, it also
 * has functions specific to a slave, e.g. to send range changes
 * and get the address ranges that the port responds to.
 */
class SlavePort : public BaseSlavePort
{

    friend class MasterPort;

  private:

    MasterPort* _masterPort;

  public:

    SlavePort(const std::string& name, MemObject* owner,
              PortID id = InvalidPortID);
    virtual ~SlavePort();

    /**
     * Send an atomic snoop request packet, where the data is moved
     * and the state is updated in zero time, without interleaving
     * with other memory accesses.
     *
     * @param pkt Snoop packet to send.
     *
     * @return Estimated latency of access.
     */
    Tick sendAtomicSnoop(PacketPtr pkt);

    /**
     * Send a functional snoop request packet, where the data is
     * instantly updated everywhere in the memory system, without
     * affecting the current state of any block or moving the block.
     *
     * @param pkt Snoop packet to send.
     */
    void sendFunctionalSnoop(PacketPtr pkt);

    /**
     * Attempt to send a timing response to the master port by calling
     * its corresponding receive function. If the send does not
     * succeed, as indicated by the return value, then the sender must
     * wait for a recvRetry at which point it can re-issue a
     * sendTimingResp.
     *
     * @param pkt Packet to send.
     *
     * @return If the send was succesful or not.
    */
    bool sendTimingResp(PacketPtr pkt);

    /**
     * Attempt to send a timing snoop request packet to the master port
     * by calling its corresponding receive function. Snoop requests
     * always succeed and hence no return value is needed.
     *
     * @param pkt Packet to send.
     */
    void sendTimingSnoopReq(PacketPtr pkt);

    /**
     * Send a retry to the master port that previously attempted a
     * sendTimingReq or sendTimingSnoopResp to this slave port and
     * failed.
     */
    void sendRetry();

    /**
     * Called by a peer port in order to determine the block size of
     * the owner of this port.
     */
    virtual unsigned deviceBlockSize() const { return 0; }

    /** Called by the associated device if it wishes to find out the blocksize
        of the device on attached to the peer port.
    */
    unsigned peerBlockSize() const;

    /**
     * Find out if the peer master port is snooping or not.
     *
     * @return true if the peer master port is snooping
     */
    bool isSnooping() const { return _masterPort->isSnooping(); }

    /**
     * Called by the owner to send a range change
     */
    void sendRangeChange() const { _masterPort->recvRangeChange(); }

    /**
     * Get a list of the non-overlapping address ranges the owner is
     * responsible for. All slave ports must override this function
     * and return a populated list with at least one item.
     *
     * @return a list of ranges responded to
     */
    virtual AddrRangeList getAddrRanges() const = 0;

  protected:

    /**
     * Called by the master port to unbind. Should never be called
     * directly.
     */
    void unbind();

    /**
     * Called by the master port to bind. Should never be called
     * directly.
     */
    void bind(MasterPort& master_port);

    /**
     * Receive an atomic request packet from the master port.
     */
    virtual Tick recvAtomic(PacketPtr pkt) = 0;

    /**
     * Receive a functional request packet from the master port.
     */
    virtual void recvFunctional(PacketPtr pkt) = 0;

    /**
     * Receive a timing request from the master port.
     */
    virtual bool recvTimingReq(PacketPtr pkt) = 0;

    /**
     * Receive a timing snoop response from the master port.
     */
    virtual bool recvTimingSnoopResp(PacketPtr pkt)
    {
        panic("%s was not expecting a timing snoop response\n", name());
    }

    /**
     * Called by the master port if sendTimingResp was called on this
     * slave port (causing recvTimingResp to be called on the master
     * port) and was unsuccesful.
     */
    virtual void recvRetry() = 0;

};

#endif //__MEM_PORT_HH__
<|endoftext|>


<commit_before>#include <string>
#include <sstream>
#include <pthread.h>
#include <vector>
#include "messages.h"
#include "signals.h"
#include "log.h"
#include "database.h"

using namespace std;

// from client.cc
extern void kill_job(int job_id);
extern void kill_client(int method);

const int MESSAGE_WAIT_TIME = 10;

static MYSQL* connection;
static bool finished;
static pthread_t thread;
static pthread_mutex_t msgs_mutex = PTHREAD_MUTEX_INITIALIZER;
static int client_id;
static vector<string> msgs;
/**
 * Checks if there are any messages in the client's database entry
 * and processes them. Also clears the message column in the process to
 * indicate that the messages have been handled.
 */
void check_message() {
    string message;
    defer_signals();
    if (get_message(client_id, message, connection) == 0) {
        reset_signal_handler();
        return;
    }
    reset_signal_handler();
    stringstream str(message);
    string line;
    pthread_mutex_lock(&msgs_mutex);
    while (getline(str, line)) {
        msgs.push_back(line);
    }
    pthread_mutex_unlock(&msgs_mutex);
}

void *message_thread(void* ptr) {
    log_message(LOG_INFO, "Message thread started.");
    if (!get_new_connection(connection)) {
        log_error(AT, "Could not establish database connection.");
        return NULL;
    }
    int time = 0;
    while (!finished) {
        if (time >= MESSAGE_WAIT_TIME) {
            check_message();
            time = 0;
        }
        sleep(1);
        time++;
    }
    mysql_close(connection);
    return NULL;
}

void start_message_thread(int _client_id) {
    client_id = _client_id;
    finished = false;
    pthread_create( &thread, NULL, message_thread, NULL);
}

void stop_message_thread() {
    finished = true;
    log_message(LOG_INFO, "Waiting for message thread..");
    pthread_join(thread, NULL);
    log_message(LOG_INFO, "..done.");
}

/**
 * Should be called by the main loop to process pending messages.
 */
void process_messages() {
    pthread_mutex_lock(&msgs_mutex);
    // copy the vector, we want to unlock the mutex as fast as possible
    vector<string> tmp = msgs;
    msgs.clear();
    pthread_mutex_unlock(&msgs_mutex);

    // process messages
    vector<string>::iterator it;
    for ( it=tmp.begin() ; it < tmp.end(); it++ ) {
        log_message(LOG_DEBUG, "Processing message: \"%s\"", it->c_str());
        istringstream ss(*it);
        string cmd;
        ss >> cmd;

        if (cmd == "kill") {
            int job_id;
            ss >> job_id;
            if (job_id != 0)
                kill_job(job_id);
        }
        else if (cmd == "kill_client") {
            string method;
            ss >> method;
            if (method == "soft") {
                kill_client(0);
            }
            else if (method == "hard") {
                kill_client(1);
            }
        }
    }
}
<commit_msg>+= comments<commit_after>#include <string>
#include <sstream>
#include <pthread.h>
#include <vector>
#include "messages.h"
#include "signals.h"
#include "log.h"
#include "database.h"

using namespace std;

// from client.cc
extern void kill_job(int job_id);
extern void kill_client(int method);

const int MESSAGE_WAIT_TIME = 10;

static MYSQL* connection;
static bool finished;
static pthread_t thread;
static pthread_mutex_t msgs_mutex = PTHREAD_MUTEX_INITIALIZER;
static int client_id;
static vector<string> msgs;

/**
 * Checks if there are any messages in the client's database entry
 * and processes them. Also clears the message column in the process to
 * indicate that the messages have been handled.
 */
void check_message() {
    string message;
    defer_signals();
    if (get_message(client_id, message, connection) == 0) {
        reset_signal_handler();
        return;
    }
    reset_signal_handler();
    stringstream str(message);
    string line;
    pthread_mutex_lock(&msgs_mutex);
    while (getline(str, line)) {
        msgs.push_back(line);
    }
    pthread_mutex_unlock(&msgs_mutex);
}

/**
 * The message thread. Receives messages and puts them into a queue.
 */
void *message_thread(void* ptr) {
    log_message(LOG_INFO, "Message thread started.");
    if (!get_new_connection(connection)) {
        log_error(AT, "Could not establish database connection.");
        return NULL;
    }
    int time = 0;
    while (!finished) {
        if (time >= MESSAGE_WAIT_TIME) {
            check_message();
            time = 0;
        }
        sleep(1);
        time++;
    }
    mysql_close(connection);
    return NULL;
}

/**
 * Starts the message thread. This method will return immediately after creating the thread.
 */
void start_message_thread(int _client_id) {
    client_id = _client_id;
    finished = false;
    pthread_create( &thread, NULL, message_thread, NULL);
}

/**
 * Stops the message thread. Waits until the message thread did a clean shutdown.
 */
void stop_message_thread() {
    finished = true;
    log_message(LOG_INFO, "Waiting for message thread..");
    pthread_join(thread, NULL);
    log_message(LOG_INFO, "..done.");
}

/**
 * Should be called by the main loop to process pending messages.
 */
void process_messages() {
    pthread_mutex_lock(&msgs_mutex);
    // copy the vector, we want to unlock the mutex as fast as possible
    vector<string> tmp = msgs;
    msgs.clear();
    pthread_mutex_unlock(&msgs_mutex);

    // process messages
    vector<string>::iterator it;
    for ( it=tmp.begin() ; it < tmp.end(); it++ ) {
        log_message(LOG_DEBUG, "Processing message: \"%s\"", it->c_str());
        istringstream ss(*it);
        string cmd;
        ss >> cmd;

        if (cmd == "kill") {
            int job_id;
            ss >> job_id;
            if (job_id != 0)
                kill_job(job_id);
        }
        else if (cmd == "kill_client") {
            string method;
            ss >> method;
            if (method == "soft") {
                kill_client(0);
            }
            else if (method == "hard") {
                kill_client(1);
            }
        }
    }
}
<|endoftext|>


<commit_before>/*
* this file is part of the oxygen gtk engine
* Copyright (c) 2010 Hugo Pereira Da Costa <hugo@oxygen-icons.org>
* Copyright (c) 2010 Ruslan Kabatsayev <b7.10110111@gmail.com>
*
* 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 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., 51  Franklin St, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/

#include <gtk/gtk.h>
#include "oxygeninnershadowdata.h"
#include "../oxygengtkutils.h"
#include "../config.h"
#include "../oxygencairocontext.h"
#include "oxygenanimations.h"
#include "../oxygenstyle.h"
#include "../oxygenmetrics.h"
#include <stdlib.h>

#include <cassert>
#include <iostream>

namespace Oxygen
{

    //_____________________________________________
    void InnerShadowData::connect( GtkWidget* widget )
    {

        assert( GTK_IS_SCROLLED_WINDOW( widget ) );
        assert( !_target );

        // store target
        _target = widget;

        if( gdk_display_supports_composite( gtk_widget_get_display( widget ) ) && G_OBJECT_TYPE_NAME(widget) != std::string("GtkPizza") )
        {
            _compositeEnabled = true;
            _exposeId.connect( G_OBJECT(_target), "expose-event", G_CALLBACK( targetExposeEvent ), this, true );
        }

        // check child
        GtkWidget* child( gtk_bin_get_child( GTK_BIN( widget ) ) );
        if( !child ) return;

        #if OXYGEN_DEBUG
        std::cerr
            << "Oxygen::InnerShadowData::connect -"
            << " widget: " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
            << " child: " << child << " (" << G_OBJECT_TYPE_NAME( child ) << ")"
            << std::endl;
        #endif

        registerChild( child );

    }

    //_____________________________________________
    void InnerShadowData::disconnect( GtkWidget* widget )
    {
        _target = 0;
        for( ChildDataMap::iterator iter = _childrenData.begin(); iter != _childrenData.end(); ++iter )
        { iter->second.disconnect( iter->first ); }

        // disconnect signals
        _exposeId.disconnect();

        // clear child data
        _childrenData.clear();
    }

    //_____________________________________________
    void InnerShadowData::registerChild( GtkWidget* widget )
    {

        #if GTK_CHECK_VERSION(2,22,0)

        // make sure widget is not already in map
        if( _childrenData.find( widget ) == _childrenData.end() )
        {

            #if OXYGEN_DEBUG
            std::cerr
                << "Oxygen::InnerShadowData::registerChild -"
                << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
                << std::endl;
            #endif

            ChildData data;
            data._unrealizeId.connect( G_OBJECT(widget), "unrealize", G_CALLBACK( childUnrealizeNotifyEvent ), this );

            GdkWindow* window(gtk_widget_get_window(widget));
            if(
                // check window
                ( window && gdk_display_supports_composite( gdk_drawable_get_display( GDK_DRAWABLE( window ) ) ) ) &&

                // check widget type (might move to blacklist method)
                ( G_OBJECT_TYPE_NAME(widget) != std::string("GtkPizza") ) &&

                // make sure widget is scrollable
                ( GTK_WIDGET_GET_CLASS( widget )->set_scroll_adjustments_signal ) )
            {
                data.initiallyComposited=gdk_window_get_composited(window);
                gdk_window_set_composited(window,TRUE);
            }

            _childrenData.insert( std::make_pair( widget, data ) );

        }

        #endif

    }

    //________________________________________________________________________________
    void InnerShadowData::unregisterChild( GtkWidget* widget )
    {

        ChildDataMap::iterator iter( _childrenData.find( widget ) );
        if( iter == _childrenData.end() ) return;

        #if OXYGEN_DEBUG
        std::cerr
            << "Oxygen::InnerShadowData::unregisterChild -"
            << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
            << std::endl;
        #endif

        iter->second.disconnect( widget );
        _childrenData.erase( iter );

    }

    //________________________________________________________________________________
    void InnerShadowData::ChildData::disconnect( GtkWidget* widget )
    {

        #if OXYGEN_DEBUG
        std::cerr
            << "Oxygen::InnerShadowData::ChildData::disconnect -"
            << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
            << std::endl;
        #endif

        // disconnect signals
        _unrealizeId.disconnect();

        // remove compositing flag
        GdkWindow* window( gtk_widget_get_window( widget ) );
        if( GTK_IS_WINDOW( window ) && G_OBJECT_TYPE_NAME( widget ) != std::string("GtkPizza") )
        { gdk_window_set_composited(window,initiallyComposited); }
    }

    //____________________________________________________________________________________________
    gboolean InnerShadowData::childUnrealizeNotifyEvent( GtkWidget* widget, gpointer data )
    {
        #if OXYGEN_DEBUG
        std::cerr
            << "Oxygen::InnerShadowData::childUnrealizeNotifyEvent -"
            << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
            << std::endl;
        #endif
        static_cast<InnerShadowData*>(data)->unregisterChild( widget );
        return FALSE;
    }

    //_________________________________________________________________________________________
    gboolean InnerShadowData::targetExposeEvent( GtkWidget* widget, GdkEventExpose* event, gpointer )
    {

        #if GTK_CHECK_VERSION(2,24,0)
        GtkWidget* child=gtk_bin_get_child(GTK_BIN(widget));
        GdkWindow* window=gtk_widget_get_window(child);

        #if OXYGEN_DEBUG
        std::cerr << "Oxygen::InnerShadowData::targetExposeEvent -"
            << " widget: " << widget << " (" << G_OBJECT_TYPE_NAME(widget) << ")"
            << " child: " << child << " (" << G_OBJECT_TYPE_NAME(widget) << ")"
            << " path: " << Gtk::gtk_widget_path( child )
            << " area: " << event->area
            << std::endl;
        #endif

        if(!gdk_window_get_composited(window))
        {
            #if OXYGEN_DEBUG
            std::cerr << "Oxygen::InnerShadowData::targetExposeEvent - Window isn't composite. Doing nohing\n";
            #endif
            return FALSE;
        }

        // make sure the child window doesn't contain garbage
        gdk_window_process_updates(window,TRUE);

        // get window geometry
        GtkAllocation allocation( Gtk::gdk_rectangle() );
        gdk_window_get_geometry( window, &allocation.x, &allocation.y, &allocation.width, &allocation.height, 0L );

        // create context with clipping
        Cairo::Context context(gtk_widget_get_window(widget), &allocation );

        // add event region
        gdk_cairo_region(context,event->region);
        cairo_clip(context);

        // draw child
        gdk_cairo_set_source_window( context, window, allocation.x, allocation.y );
        cairo_paint(context);

        #if OXYGEN_DEBUG_INNERSHADOWS
        // Show updated parts in random color
        cairo_rectangle(context,allocation.x,allocation.y,allocation.width,allocation.height);
        double red=((double)rand())/RAND_MAX;
        double green=((double)rand())/RAND_MAX;
        double blue=((double)rand())/RAND_MAX;
        cairo_set_source_rgba(context,red,green,blue,0.5);
        cairo_fill(context);
        #endif

        // draw the shadow
        /*
        TODO: here child widget's allocation is used instead of window geometry.
        I think this is the correct thing to do (unlike above), but this is to be double check
        */
        allocation = Gtk::gtk_widget_get_allocation( child );
        int basicOffset=2;

        // we only draw SHADOW_IN here
        if(gtk_scrolled_window_get_shadow_type(GTK_SCROLLED_WINDOW(widget)) != GTK_SHADOW_IN )
        {
            if( GTK_IS_VIEWPORT(child) && gtk_viewport_get_shadow_type(GTK_VIEWPORT(child)) == GTK_SHADOW_IN )
            {

                basicOffset=0;

            } else {

                // FIXME: do we need this special case?
                // special_case {
                // we still want to draw shadow on GtkFrames with shadow containing GtkScrolledWindow without shadow
                GtkWidget* box=gtk_widget_get_parent(widget);
                GtkWidget* frame=0;
                if(GTK_IS_BOX(box) && GTK_IS_FRAME(frame=gtk_widget_get_parent(box)) &&
                       gtk_frame_get_shadow_type(GTK_FRAME(frame))==GTK_SHADOW_IN)
                {
                    #if OXYGEN_DEBUG
                    std::cerr << "Oxygen::InnerShadowData::targetExposeEvent: Box children: " << GTK_CONTAINER(box) << std::endl;
                    #endif
                    // make sure GtkScrolledWindow is the only visible child
                    GList* children=gtk_container_get_children(GTK_CONTAINER(box));
                    for(GList* child=g_list_first(children); child; child=g_list_next(child))
                    {
                        GtkWidget* childWidget(GTK_WIDGET(child->data));
                        if(gtk_widget_get_visible(childWidget) && !GTK_IS_SCROLLED_WINDOW(childWidget))
                        {
                            g_list_free(children);
                            return FALSE;
                        }
                    }
                    int frameX, frameY;
                    GtkAllocation frameAlloc;
                    if(gtk_widget_translate_coordinates(frame,widget,0,0,&frameX,&frameY))
                    {
                        #if OXYGEN_DEBUG
                        std::cerr << "coords translation: x=" << frameX << "; y=" << frameY << std::endl;
                        #endif
                        gtk_widget_get_allocation(frame,&frameAlloc);
                        allocation.x+=frameX;
                        allocation.y+=frameY;
                        allocation.width=frameAlloc.width;
                        allocation.height=frameAlloc.height;
                        basicOffset=0;
                    }

                } else {

                    #if OXYGEN_DEBUG
                    std::cerr << "Oxygen::InnerShadowData::targetExposeEvent - Shadow type isn't GTK_SHADOW_IN, so not drawing the shadow in expose-event handler\n";
                    #endif
                    return FALSE;

                }

            }
        }

        StyleOptions options(widget,gtk_widget_get_state(widget));
        options|=NoFill;
        options &= ~(Hover|Focus);
        if( Style::instance().animations().scrolledWindowEngine().contains( widget ) )
        {
            if( Style::instance().animations().scrolledWindowEngine().focused( widget ) ) options |= Focus;
            if( Style::instance().animations().scrolledWindowEngine().hovered( widget ) ) options |= Hover;
        }

        const AnimationData data( Style::instance().animations().widgetStateEngine().get( widget, options, AnimationHover|AnimationFocus, AnimationFocus ) );

        int offsetX=basicOffset+Entry_SideMargin;
        int offsetY=basicOffset;

        // clipRect
        GdkRectangle clipRect( allocation );

        // hole background
        Style::instance().renderHoleBackground(
            gtk_widget_get_window(widget), widget, &clipRect,
            allocation.x-offsetX, allocation.y-offsetY, allocation.width+offsetX*2, allocation.height+offsetY*2 );

        // adjust offset and render hole
        offsetX -= Entry_SideMargin;
        Style::instance().renderHole(
            gtk_widget_get_window(widget), &clipRect,
            allocation.x-offsetX, allocation.y-offsetY, allocation.width+offsetX*2, allocation.height+offsetY*2,
            options, data );

        #endif // Gtk version

        // let the event propagate
        return FALSE;
    }

}
<commit_msg>only set compositing on windows of type GDK_WINDOW_CHILD CCBUG: 286140<commit_after>/*
* this file is part of the oxygen gtk engine
* Copyright (c) 2010 Hugo Pereira Da Costa <hugo@oxygen-icons.org>
* Copyright (c) 2010 Ruslan Kabatsayev <b7.10110111@gmail.com>
*
* 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 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., 51  Franklin St, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/

#include <gtk/gtk.h>
#include "oxygeninnershadowdata.h"
#include "../oxygengtkutils.h"
#include "../config.h"
#include "../oxygencairocontext.h"
#include "oxygenanimations.h"
#include "../oxygenstyle.h"
#include "../oxygenmetrics.h"
#include <stdlib.h>

#include <cassert>
#include <iostream>

namespace Oxygen
{

    //_____________________________________________
    void InnerShadowData::connect( GtkWidget* widget )
    {

        assert( GTK_IS_SCROLLED_WINDOW( widget ) );
        assert( !_target );

        // store target
        _target = widget;

        if( gdk_display_supports_composite( gtk_widget_get_display( widget ) ) && G_OBJECT_TYPE_NAME(widget) != std::string("GtkPizza") )
        {
            _compositeEnabled = true;
            _exposeId.connect( G_OBJECT(_target), "expose-event", G_CALLBACK( targetExposeEvent ), this, true );
        }

        // check child
        GtkWidget* child( gtk_bin_get_child( GTK_BIN( widget ) ) );
        if( !child ) return;

        #if OXYGEN_DEBUG
        std::cerr
            << "Oxygen::InnerShadowData::connect -"
            << " widget: " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
            << " child: " << child << " (" << G_OBJECT_TYPE_NAME( child ) << ")"
            << std::endl;
        #endif

        registerChild( child );

    }

    //_____________________________________________
    void InnerShadowData::disconnect( GtkWidget* widget )
    {
        _target = 0;
        for( ChildDataMap::iterator iter = _childrenData.begin(); iter != _childrenData.end(); ++iter )
        { iter->second.disconnect( iter->first ); }

        // disconnect signals
        _exposeId.disconnect();

        // clear child data
        _childrenData.clear();
    }

    //_____________________________________________
    void InnerShadowData::registerChild( GtkWidget* widget )
    {

        #if GTK_CHECK_VERSION(2,22,0)

        // make sure widget is not already in map
        if( _childrenData.find( widget ) == _childrenData.end() )
        {

            #if OXYGEN_DEBUG
            std::cerr
                << "Oxygen::InnerShadowData::registerChild -"
                << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
                << std::endl;
            #endif

            ChildData data;
            data._unrealizeId.connect( G_OBJECT(widget), "unrealize", G_CALLBACK( childUnrealizeNotifyEvent ), this );

            GdkWindow* window(gtk_widget_get_window(widget));
            if(
                // check window
                window &&
                gdk_display_supports_composite( gdk_drawable_get_display( GDK_DRAWABLE( window ) ) ) &&
                gdk_window_get_window_type( window ) == GDK_WINDOW_CHILD &&

                // check widget type (might move to blacklist method)
                ( G_OBJECT_TYPE_NAME(widget) != std::string("GtkPizza") ) &&

                // make sure widget is scrollable
                GTK_WIDGET_GET_CLASS( widget )->set_scroll_adjustments_signal )
            {
                data.initiallyComposited=gdk_window_get_composited(window);
                gdk_window_set_composited(window,TRUE);
            }

            _childrenData.insert( std::make_pair( widget, data ) );

        }

        #endif

    }

    //________________________________________________________________________________
    void InnerShadowData::unregisterChild( GtkWidget* widget )
    {

        ChildDataMap::iterator iter( _childrenData.find( widget ) );
        if( iter == _childrenData.end() ) return;

        #if OXYGEN_DEBUG
        std::cerr
            << "Oxygen::InnerShadowData::unregisterChild -"
            << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
            << std::endl;
        #endif

        iter->second.disconnect( widget );
        _childrenData.erase( iter );

    }

    //________________________________________________________________________________
    void InnerShadowData::ChildData::disconnect( GtkWidget* widget )
    {

        #if OXYGEN_DEBUG
        std::cerr
            << "Oxygen::InnerShadowData::ChildData::disconnect -"
            << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
            << std::endl;
        #endif

        // disconnect signals
        _unrealizeId.disconnect();

        // remove compositing flag
        GdkWindow* window( gtk_widget_get_window( widget ) );
        if( GTK_IS_WINDOW( window ) && G_OBJECT_TYPE_NAME( widget ) != std::string("GtkPizza") )
        { gdk_window_set_composited(window,initiallyComposited); }
    }

    //____________________________________________________________________________________________
    gboolean InnerShadowData::childUnrealizeNotifyEvent( GtkWidget* widget, gpointer data )
    {
        #if OXYGEN_DEBUG
        std::cerr
            << "Oxygen::InnerShadowData::childUnrealizeNotifyEvent -"
            << " " << widget << " (" << G_OBJECT_TYPE_NAME( widget ) << ")"
            << std::endl;
        #endif
        static_cast<InnerShadowData*>(data)->unregisterChild( widget );
        return FALSE;
    }

    //_________________________________________________________________________________________
    gboolean InnerShadowData::targetExposeEvent( GtkWidget* widget, GdkEventExpose* event, gpointer )
    {

        #if GTK_CHECK_VERSION(2,24,0)
        GtkWidget* child=gtk_bin_get_child(GTK_BIN(widget));
        GdkWindow* window=gtk_widget_get_window(child);

        #if OXYGEN_DEBUG
        std::cerr << "Oxygen::InnerShadowData::targetExposeEvent -"
            << " widget: " << widget << " (" << G_OBJECT_TYPE_NAME(widget) << ")"
            << " child: " << child << " (" << G_OBJECT_TYPE_NAME(widget) << ")"
            << " path: " << Gtk::gtk_widget_path( child )
            << " area: " << event->area
            << std::endl;
        #endif

        if(!gdk_window_get_composited(window))
        {
            #if OXYGEN_DEBUG
            std::cerr << "Oxygen::InnerShadowData::targetExposeEvent - Window isn't composite. Doing nohing\n";
            #endif
            return FALSE;
        }

        // make sure the child window doesn't contain garbage
        gdk_window_process_updates(window,TRUE);

        // get window geometry
        GtkAllocation allocation( Gtk::gdk_rectangle() );
        gdk_window_get_geometry( window, &allocation.x, &allocation.y, &allocation.width, &allocation.height, 0L );

        // create context with clipping
        Cairo::Context context(gtk_widget_get_window(widget), &allocation );

        // add event region
        gdk_cairo_region(context,event->region);
        cairo_clip(context);

        // draw child
        gdk_cairo_set_source_window( context, window, allocation.x, allocation.y );
        cairo_paint(context);

        #if OXYGEN_DEBUG_INNERSHADOWS
        // Show updated parts in random color
        cairo_rectangle(context,allocation.x,allocation.y,allocation.width,allocation.height);
        double red=((double)rand())/RAND_MAX;
        double green=((double)rand())/RAND_MAX;
        double blue=((double)rand())/RAND_MAX;
        cairo_set_source_rgba(context,red,green,blue,0.5);
        cairo_fill(context);
        #endif

        // draw the shadow
        /*
        TODO: here child widget's allocation is used instead of window geometry.
        I think this is the correct thing to do (unlike above), but this is to be double check
        */
        allocation = Gtk::gtk_widget_get_allocation( child );
        int basicOffset=2;

        // we only draw SHADOW_IN here
        if(gtk_scrolled_window_get_shadow_type(GTK_SCROLLED_WINDOW(widget)) != GTK_SHADOW_IN )
        {
            if( GTK_IS_VIEWPORT(child) && gtk_viewport_get_shadow_type(GTK_VIEWPORT(child)) == GTK_SHADOW_IN )
            {

                basicOffset=0;

            } else {

                // FIXME: do we need this special case?
                // special_case {
                // we still want to draw shadow on GtkFrames with shadow containing GtkScrolledWindow without shadow
                GtkWidget* box=gtk_widget_get_parent(widget);
                GtkWidget* frame=0;
                if(GTK_IS_BOX(box) && GTK_IS_FRAME(frame=gtk_widget_get_parent(box)) &&
                       gtk_frame_get_shadow_type(GTK_FRAME(frame))==GTK_SHADOW_IN)
                {
                    #if OXYGEN_DEBUG
                    std::cerr << "Oxygen::InnerShadowData::targetExposeEvent: Box children: " << GTK_CONTAINER(box) << std::endl;
                    #endif
                    // make sure GtkScrolledWindow is the only visible child
                    GList* children=gtk_container_get_children(GTK_CONTAINER(box));
                    for(GList* child=g_list_first(children); child; child=g_list_next(child))
                    {
                        GtkWidget* childWidget(GTK_WIDGET(child->data));
                        if(gtk_widget_get_visible(childWidget) && !GTK_IS_SCROLLED_WINDOW(childWidget))
                        {
                            g_list_free(children);
                            return FALSE;
                        }
                    }
                    int frameX, frameY;
                    GtkAllocation frameAlloc;
                    if(gtk_widget_translate_coordinates(frame,widget,0,0,&frameX,&frameY))
                    {
                        #if OXYGEN_DEBUG
                        std::cerr << "coords translation: x=" << frameX << "; y=" << frameY << std::endl;
                        #endif
                        gtk_widget_get_allocation(frame,&frameAlloc);
                        allocation.x+=frameX;
                        allocation.y+=frameY;
                        allocation.width=frameAlloc.width;
                        allocation.height=frameAlloc.height;
                        basicOffset=0;
                    }

                } else {

                    #if OXYGEN_DEBUG
                    std::cerr << "Oxygen::InnerShadowData::targetExposeEvent - Shadow type isn't GTK_SHADOW_IN, so not drawing the shadow in expose-event handler\n";
                    #endif
                    return FALSE;

                }

            }
        }

        StyleOptions options(widget,gtk_widget_get_state(widget));
        options|=NoFill;
        options &= ~(Hover|Focus);
        if( Style::instance().animations().scrolledWindowEngine().contains( widget ) )
        {
            if( Style::instance().animations().scrolledWindowEngine().focused( widget ) ) options |= Focus;
            if( Style::instance().animations().scrolledWindowEngine().hovered( widget ) ) options |= Hover;
        }

        const AnimationData data( Style::instance().animations().widgetStateEngine().get( widget, options, AnimationHover|AnimationFocus, AnimationFocus ) );

        int offsetX=basicOffset+Entry_SideMargin;
        int offsetY=basicOffset;

        // clipRect
        GdkRectangle clipRect( allocation );

        // hole background
        Style::instance().renderHoleBackground(
            gtk_widget_get_window(widget), widget, &clipRect,
            allocation.x-offsetX, allocation.y-offsetY, allocation.width+offsetX*2, allocation.height+offsetY*2 );

        // adjust offset and render hole
        offsetX -= Entry_SideMargin;
        Style::instance().renderHole(
            gtk_widget_get_window(widget), &clipRect,
            allocation.x-offsetX, allocation.y-offsetY, allocation.width+offsetX*2, allocation.height+offsetY*2,
            options, data );

        #endif // Gtk version

        // let the event propagate
        return FALSE;
    }

}
<|endoftext|>


<commit_before>#include "Riostream.h"
#include "TMatrixD.h"
#include "TMatrixDLazy.h"
#include "TVectorD.h"
#include "TDecompLU.h"
#include "TDecompSVD.h"

// This macro shows several ways to invert a matrix . Each  method
// is a trade-off between accuracy of the inversion and speed.
// Which method to chose depends on "how well-behaved" the matrix is.
// This is best checked through a call to Condition(), available in each
// decomposition class. A second possibilty (less preferred) would be to
// check the determinant
//
// You can run this script with different matrix sizes

void invertMatrix(Int_t msize=6)
{
  if (msize < 2 || msize > 10) {
    cout << "2 <= msize <= 10" <<endl;
    return;
  }
  cout << "--------------------------------------------------------" <<endl;
  cout << "Inversion results for a ("<<msize<<","<<msize<<") matrix" <<endl;
  cout << "For each inversion procedure we check the maxmimum size " <<endl;
  cout << "of the off-diagonal elements of Inv(A) * A              " <<endl;
  cout << "--------------------------------------------------------" <<endl;

  TMatrixD H_square = THilbertMatrixD(msize,msize);

//  1. InvertFast(Double_t *det=0)
//   This method is only available for the matrix class TMatrixD/F, because an
//   symmetric matrix is not necessarily symmetric after inversion .
//   It is identical to Invert() for sizes > 6 x 6 but for smaller sizes, the
//   inversion is performed according to Cramer's rule by explicitly calculating
//   all Jacobi's sub-determinants . For instance for a 6 x 6 matrix this means:
//    # of 5 x 5 determinant : 36
//    # of 4 x 4 determinant : 75
//    # of 3 x 3 determinant : 80
//    # of 2 x 2 determinant : 45    (see TMatrixD/FCramerInv.cxx)
//
//    The only "quality" control in this process is to check whether the 6 x 6
//    determinant is unequal 0 . But speed gains are significant compared to Invert() ,
//    upto an order of magnitude for sizes <= 4 x 4
//
//    The inversion is done "in place", so the original matrix will be overwritten
//    If a pointer to a Double_t is supplied the determinant is calculated
//

  cout << "1. Use .InvertFast(&det)" <<endl;
  if (msize > 6)
    cout << " for ("<<msize<<","<<msize<<") this is identical to .Invert(&det)" <<endl;

  Double_t det1;
  TMatrixD H1 = H_square;
  H1.InvertFast(&det1);

  // Get the maximum off-diagonal matrix value . One way to do this is to set the
  // diagonal to zero .

  TMatrixD U1(H1,TMatrixD::kMult,H_square);
  TMatrixDDiag diag1(U1); diag1 = 0.0;
  const Double_t U1_max_offdiag = (U1.Abs()).Max();
  cout << "  Maximum off-diagonal = " << U1_max_offdiag << endl;
  cout << "  Determinant          = " << det1 <<endl;

// 2. Invert(Double_t *det=0)
//   Also only available for TMatrixD/F . Again the inversion is performed in place .
//   It consists out of a sequence of calls related to the LU decomposition:
//    - The matrix is decomposed using a scheme according to Crout which involves
//      "implicit partial pivoting", see for instance Num. Recip. (we have also available
//      a decomposition scheme that does not the scaling and is therefore even slightly
//      faster but less stable)
//      With each decomposition, a tolerance has to be specified . If this tolerance
//      requirement is not met, the matrix is regarded as being singular. The value
//      passed to this decomposition, is the data member fTol of the matrix . Its
//      default value is DBL_EPSILON, which is defined as the smallest nuber so that
//      1+DBL_EPSILON > 1
//    - The last step is a standard forward/backward substitution .
//
//   It is important to realize that both InvertFast() and Invert() are "one-shot" deals , speed
//   comes at a price . If something goes wrong because the matrix is (near) singular, you have
//   overwritten your original matrix and  no factorization is available anymore to get more
//   information like condition number or change the tolerance number .
//
//   All other calls in the matrix classes involving inversion like the ones with the "smart"
//   constructors (kInverted,kInvMult...) use this inversion method .
//

  cout << "2. Use .Invert(&det)" <<endl;
  cout << "  If the determinant is < 2^-52 (="<<TMath::Power(2,-52)<<"), a warning is generated" <<endl;

  Double_t det2;
  TMatrixD H2 = H_square;
  H2.Invert(&det2);

  TMatrixD U2(H2,TMatrixD::kMult,H_square);
  TMatrixDDiag diag2(U2); diag2 = 0.0;
  const Double_t U2_max_offdiag = (U2.Abs()).Max();
  cout << "  Maximum off-diagonal = " << U2_max_offdiag << endl;
  cout << "  Determinant          = " << det2 <<endl;

// 3. Inversion through LU decomposition
//   The (default) algorithms used are similar to 2. (Not identical because in 2, the whole
//   calculation is done "in-place". Here the orginal matrix is copied (so more memory
//   management => slower) and several operations can be performed without having to repeat
//   the decomposition step .
//   Inverting a matrix is nothing else than solving a set of equations where the rhs is given
//   by the unit matrix, so the steps to take are identical to those solving a linear equation :
//

  cout << "3. Use TDecompLU" <<endl;

  TMatrixD H3 = H_square;
  TDecompLU lu(H_square);

  // Any operation that requires a decomposition will trigger it . The class keeps
  // an internal state so that following operations will not perform the decomposition again
  // unless the matrix is changed through SetMatrix(..)
  // One might want to proceed more cautiously by invoking first Decompose() and check its
  // return value before proceeding....

  lu.Invert(H3);
  Double_t d1_lu; Double_t d2_lu;
  lu.Det(d1_lu,d2_lu);
  Double_t det3 = d1_lu*TMath::Power(2.,d2_lu);

  TMatrixD U3(H3,TMatrixD::kMult,H_square);
  TMatrixDDiag diag3(U3); diag3 = 0.0;
  const Double_t U3_max_offdiag = (U3.Abs()).Max();
  cout << "  Maximum off-diagonal = " << U3_max_offdiag << endl;
  cout << "  Determinant          = " << det3 <<endl;

// 4. Inversion through SVD decomposition
//   For SVD and QRH, the (n x m) matrix does only have to fulfill n >=m . In case n > m
//   a pseudo-inverse is calculated
  cout << "4. Use TDecompSVD on non-square matrix" <<endl;

  TMatrixD H_nsquare = THilbertMatrixD(msize,msize-1);

  TDecompSVD svd(H_nsquare);

  TMatrixD H4 = svd.Invert();
  Double_t d1_svd; Double_t d2_svd;
  svd.Det(d1_svd,d2_svd);
  Double_t det4 = d1_svd*TMath::Power(2.,d2_svd);

  TMatrixD U4(H4,TMatrixD::kMult,H_nsquare);
  TMatrixDDiag diag4(U4); diag4 = 0.0;
  const Double_t U4_max_offdiag = (U4.Abs()).Max();
  cout << "  Maximum off-diagonal = " << U4_max_offdiag << endl;
  cout << "  Determinant          = " << det4 <<endl;
}
<commit_msg>From Eddy Offermann: After the introduction of the Bnch-Kaufman decomposition for symmetric matrices, we have to update some comments in the invertMatrix.C tutorial,<commit_after>#include "Riostream.h"
#include "TMatrixD.h"
#include "TMatrixDLazy.h"
#include "TVectorD.h"
#include "TDecompLU.h"
#include "TDecompSVD.h"

// This macro shows several ways to invert a matrix . Each  method
// is a trade-off between accuracy of the inversion and speed.
// Which method to chose depends on "how well-behaved" the matrix is.
// This is best checked through a call to Condition(), available in each
// decomposition class. A second possibilty (less preferred) would be to
// check the determinant
//
// You can run this script with different matrix sizes

void invertMatrix(Int_t msize=6)
{
  if (msize < 2 || msize > 10) {
    cout << "2 <= msize <= 10" <<endl;
    return;
  }
  cout << "--------------------------------------------------------" <<endl;
  cout << "Inversion results for a ("<<msize<<","<<msize<<") matrix" <<endl;
  cout << "For each inversion procedure we check the maxmimum size " <<endl;
  cout << "of the off-diagonal elements of Inv(A) * A              " <<endl;
  cout << "--------------------------------------------------------" <<endl;

  TMatrixD H_square = THilbertMatrixD(msize,msize);

//  1. InvertFast(Double_t *det=0)
//   It is identical to Invert() for sizes > 6 x 6 but for smaller sizes, the
//   inversion is performed according to Cramer's rule by explicitly calculating
//   all Jacobi's sub-determinants . For instance for a 6 x 6 matrix this means:
//    # of 5 x 5 determinant : 36
//    # of 4 x 4 determinant : 75
//    # of 3 x 3 determinant : 80
//    # of 2 x 2 determinant : 45    (see TMatrixD/FCramerInv.cxx)
//
//    The only "quality" control in this process is to check whether the 6 x 6
//    determinant is unequal 0 . But speed gains are significant compared to Invert() ,
//    upto an order of magnitude for sizes <= 4 x 4
//
//    The inversion is done "in place", so the original matrix will be overwritten
//    If a pointer to a Double_t is supplied the determinant is calculated
//

  cout << "1. Use .InvertFast(&det)" <<endl;
  if (msize > 6)
    cout << " for ("<<msize<<","<<msize<<") this is identical to .Invert(&det)" <<endl;

  Double_t det1;
  TMatrixD H1 = H_square;
  H1.InvertFast(&det1);

  // Get the maximum off-diagonal matrix value . One way to do this is to set the
  // diagonal to zero .

  TMatrixD U1(H1,TMatrixD::kMult,H_square);
  TMatrixDDiag diag1(U1); diag1 = 0.0;
  const Double_t U1_max_offdiag = (U1.Abs()).Max();
  cout << "  Maximum off-diagonal = " << U1_max_offdiag << endl;
  cout << "  Determinant          = " << det1 <<endl;

// 2. Invert(Double_t *det=0)
//   Again the inversion is performed in place .
//   It consists out of a sequence of calls to the decomposition classes . For instance
//   for the general dense matrix TMatrixD the LU decomposition is invoked:
//    - The matrix is decomposed using a scheme according to Crout which involves
//      "implicit partial pivoting", see for instance Num. Recip. (we have also available
//      a decomposition scheme that does not the scaling and is therefore even slightly
//      faster but less stable)
//      With each decomposition, a tolerance has to be specified . If this tolerance
//      requirement is not met, the matrix is regarded as being singular. The value
//      passed to this decomposition, is the data member fTol of the matrix . Its
//      default value is DBL_EPSILON, which is defined as the smallest nuber so that
//      1+DBL_EPSILON > 1
//    - The last step is a standard forward/backward substitution .
//
//   It is important to realize that both InvertFast() and Invert() are "one-shot" deals , speed
//   comes at a price . If something goes wrong because the matrix is (near) singular, you have
//   overwritten your original matrix and  no factorization is available anymore to get more
//   information like condition number or change the tolerance number .
//
//   All other calls in the matrix classes involving inversion like the ones with the "smart"
//   constructors (kInverted,kInvMult...) use this inversion method .
//

  cout << "2. Use .Invert(&det)" <<endl;
  cout << "  If the determinant is < 2^-52 (="<<TMath::Power(2,-52)<<"), a warning is generated" <<endl;

  Double_t det2;
  TMatrixD H2 = H_square;
  H2.Invert(&det2);

  TMatrixD U2(H2,TMatrixD::kMult,H_square);
  TMatrixDDiag diag2(U2); diag2 = 0.0;
  const Double_t U2_max_offdiag = (U2.Abs()).Max();
  cout << "  Maximum off-diagonal = " << U2_max_offdiag << endl;
  cout << "  Determinant          = " << det2 <<endl;

// 3. Inversion through LU decomposition
//   The (default) algorithms used are similar to 2. (Not identical because in 2, the whole
//   calculation is done "in-place". Here the orginal matrix is copied (so more memory
//   management => slower) and several operations can be performed without having to repeat
//   the decomposition step .
//   Inverting a matrix is nothing else than solving a set of equations where the rhs is given
//   by the unit matrix, so the steps to take are identical to those solving a linear equation :
//

  cout << "3. Use TDecompLU" <<endl;

  TMatrixD H3 = H_square;
  TDecompLU lu(H_square);

  // Any operation that requires a decomposition will trigger it . The class keeps
  // an internal state so that following operations will not perform the decomposition again
  // unless the matrix is changed through SetMatrix(..)
  // One might want to proceed more cautiously by invoking first Decompose() and check its
  // return value before proceeding....

  lu.Invert(H3);
  Double_t d1_lu; Double_t d2_lu;
  lu.Det(d1_lu,d2_lu);
  Double_t det3 = d1_lu*TMath::Power(2.,d2_lu);

  TMatrixD U3(H3,TMatrixD::kMult,H_square);
  TMatrixDDiag diag3(U3); diag3 = 0.0;
  const Double_t U3_max_offdiag = (U3.Abs()).Max();
  cout << "  Maximum off-diagonal = " << U3_max_offdiag << endl;
  cout << "  Determinant          = " << det3 <<endl;

// 4. Inversion through SVD decomposition
//   For SVD and QRH, the (n x m) matrix does only have to fulfill n >=m . In case n > m
//   a pseudo-inverse is calculated
  cout << "4. Use TDecompSVD on non-square matrix" <<endl;

  TMatrixD H_nsquare = THilbertMatrixD(msize,msize-1);

  TDecompSVD svd(H_nsquare);

  TMatrixD H4 = svd.Invert();
  Double_t d1_svd; Double_t d2_svd;
  svd.Det(d1_svd,d2_svd);
  Double_t det4 = d1_svd*TMath::Power(2.,d2_svd);

  TMatrixD U4(H4,TMatrixD::kMult,H_nsquare);
  TMatrixDDiag diag4(U4); diag4 = 0.0;
  const Double_t U4_max_offdiag = (U4.Abs()).Max();
  cout << "  Maximum off-diagonal = " << U4_max_offdiag << endl;
  cout << "  Determinant          = " << det4 <<endl;
}
<|endoftext|>


<commit_before>#include "shader.h"

const char *vertex_glsl =
  "#version 330\n"
  "uniform mat4 view;"
  "uniform mat4 projection;"
  "uniform mat4 world;"
  "layout (location=1) in vec3 position;"
  "out vec3 world_position;"
  "void main()"
  "{"
    "world_position = (world * vec4(position,1.0f)).xyz;"
    "gl_Position = projection * view * world * vec4(position,1.0f);"
    // "gl_Position = vec4(position,1.0f);\n"
  "}";
const char *fragment_glsl =
  "#version 330\n"
  "layout (location = 0) out vec4 colour;"
  "in vec3 world_position;"
  "void main()"
  "{"
    "vec3 wp = world_position + vec3(100,100,100);"
    "float scale = 0.5;"
    "float xm = mod(int(wp.x*scale),2);"
    "float ym = mod(int(wp.y*scale),2);"
    "float zm = mod(int(wp.z*scale),2);"
    "float ip = 0;"
    "if ("
      "xm == zm"
      ") ip = 0.5;"
    "colour = vec4(ip,ip,ip,1);"
  "}";

// Just some helper functions for checking shaders...
void shaderLog(GLuint handle)
{
  int status;
  glGetShaderiv(handle, GL_COMPILE_STATUS, &status);
  if (status == GL_FALSE)
  {
     /* Get the length of the info log. */
     int len;
     glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &len);
     /* Get the info log. */
     char* log = new char[len];
     glGetShaderInfoLog(handle, len, &len, log);
     /* Print error */
     cerr << "Compilation error: " << log << endl;
     /* Finally, free the memory allocated. */
     delete log;
     /* Exit the program. */
     exit(-1);
  }
}

void programLog(GLuint handle)
{
  int status;
  glGetProgramiv(handle, GL_LINK_STATUS, &status);
  if (status == GL_FALSE)
  {
     /* Get the length of the info log. */
     int len;
     glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &len);
     /* Get the info log. */
     char* log = new char[len];
     glGetProgramInfoLog(handle, len, &len, log);
     /* Print error */
     cerr << "Link error: " << log << endl;
     /* Finally, free the memory allocated. */
     delete log;
     /* Exit the program. */
     exit(-1);
  }
}

<commit_msg>Fixed two more warnings<commit_after>#include "shader.h"

const char *vertex_glsl =
  "#version 330\n"
  "uniform mat4 view;"
  "uniform mat4 projection;"
  "uniform mat4 world;"
  "layout (location=1) in vec3 position;"
  "out vec3 world_position;"
  "void main()"
  "{"
    "world_position = (world * vec4(position,1.0f)).xyz;"
    "gl_Position = projection * view * world * vec4(position,1.0f);"
    // "gl_Position = vec4(position,1.0f);\n"
  "}";
const char *fragment_glsl =
  "#version 330\n"
  "layout (location = 0) out vec4 colour;"
  "in vec3 world_position;"
  "void main()"
  "{"
    "vec3 wp = world_position + vec3(100,100,100);"
    "float scale = 0.5;"
    "float xm = mod(int(wp.x*scale),2);"
    "float ym = mod(int(wp.y*scale),2);"
    "float zm = mod(int(wp.z*scale),2);"
    "float ip = 0;"
    "if ("
      "xm == zm"
      ") ip = 0.5;"
    "colour = vec4(ip,ip,ip,1);"
  "}";

// Just some helper functions for checking shaders...
void shaderLog(GLuint handle)
{
  int status;
  glGetShaderiv(handle, GL_COMPILE_STATUS, &status);
  if (status == GL_FALSE)
  {
     /* Get the length of the info log. */
     int len;
     glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &len);
     /* Get the info log. */
     char* log = new char[(unsigned)len];
     glGetShaderInfoLog(handle, len, &len, log);
     /* Print error */
     cerr << "Compilation error: " << log << endl;
     /* Finally, free the memory allocated. */
     delete log;
     /* Exit the program. */
     exit(-1);
  }
}

void programLog(GLuint handle)
{
  int status;
  glGetProgramiv(handle, GL_LINK_STATUS, &status);
  if (status == GL_FALSE)
  {
     /* Get the length of the info log. */
     int len;
     glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &len);
     /* Get the info log. */
     char* log = new char[(unsigned)len];
     glGetProgramInfoLog(handle, len, &len, log);
     /* Print error */
     cerr << "Link error: " << log << endl;
     /* Finally, free the memory allocated. */
     delete log;
     /* Exit the program. */
     exit(-1);
  }
}

<|endoftext|>


<commit_before>#include <iostream>
#include <vector>
#include <algorithm>

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE TimSortTest
#include <boost/test/unit_test.hpp>

#include "timsort.hpp"

template<typename T>
int compare(T x, T y) {
    if(x == y) {
        return 0;
    }
    else if(x < y) {
        return -1;
    }
    else {
        return 1;
    }
}

BOOST_AUTO_TEST_CASE( simple10 ) {
    std::vector<int> a;
    a.push_back(60);
    a.push_back(50);
    a.push_back( 1);
    a.push_back(40);
    a.push_back(80);
    a.push_back(20);
    a.push_back(30);
    a.push_back(70);
    a.push_back(10);
    a.push_back(90);

    timsort(a.begin(), a.end(), &compare<int>);

    BOOST_CHECK_EQUAL( a[0],  1 );
    BOOST_CHECK_EQUAL( a[1], 10 );
    BOOST_CHECK_EQUAL( a[2], 20 );
    BOOST_CHECK_EQUAL( a[3], 30 );
    BOOST_CHECK_EQUAL( a[4], 40 );
    BOOST_CHECK_EQUAL( a[5], 50 );
    BOOST_CHECK_EQUAL( a[6], 60 );
    BOOST_CHECK_EQUAL( a[7], 70 );
    BOOST_CHECK_EQUAL( a[8], 80 );
    BOOST_CHECK_EQUAL( a[9], 90 );

    std::reverse(a.begin(), a.end());

    timsort(a.begin(), a.end(), &compare<int>);

    BOOST_CHECK_EQUAL( a[0],  1 );
    BOOST_CHECK_EQUAL( a[1], 10 );
    BOOST_CHECK_EQUAL( a[2], 20 );
    BOOST_CHECK_EQUAL( a[3], 30 );
    BOOST_CHECK_EQUAL( a[4], 40 );
    BOOST_CHECK_EQUAL( a[5], 50 );
    BOOST_CHECK_EQUAL( a[6], 60 );
    BOOST_CHECK_EQUAL( a[7], 70 );
    BOOST_CHECK_EQUAL( a[8], 80 );
    BOOST_CHECK_EQUAL( a[9], 90 );
}

BOOST_AUTO_TEST_CASE( shuffle30 ) {
    const int size = 30;

    std::vector<int> a;
    for(int i = 0; i < size; ++i) {
        a.push_back((i+1) * 10);
    }
    std::random_shuffle(a.begin(), a.end());

    timsort(a.begin(), a.end(), &compare<int>);

    for(int i = 0; i < size; ++i) {
        BOOST_CHECK_EQUAL( a[i], (i+1) * 10 );
    }
}

BOOST_AUTO_TEST_CASE( shuffle31 ) {
    const int size = 31;

    std::vector<int> a;
    for(int i = 0; i < size; ++i) {
        a.push_back((i+1) * 10);
    }
    std::random_shuffle(a.begin(), a.end());

    timsort(a.begin(), a.end(), &compare<int>);

    for(int i = 0; i < size; ++i) {
        BOOST_CHECK_EQUAL( a[i], (i+1) * 10 );
    }
}

BOOST_AUTO_TEST_CASE( shuffle32 ) {
    const int size = 32;

    std::vector<int> a;
    for(int i = 0; i < size; ++i) {
        a.push_back((i+1) * 10);
    }
    std::random_shuffle(a.begin(), a.end());

    timsort(a.begin(), a.end(), &compare<int>);

    for(int i = 0; i < size; ++i) {
        BOOST_CHECK_EQUAL( a[i], (i+1) * 10 );
    }
}

BOOST_AUTO_TEST_CASE( shuffle128 ) {
    const int size = 128;

    std::vector<int> a;
    for(int i = 0; i < size; ++i) {
        a.push_back((i+1) * 10);
    }
    std::random_shuffle(a.begin(), a.end());

    timsort(a.begin(), a.end(), &compare<int>);

    for(int i = 0; i < size; ++i) {
        BOOST_CHECK_EQUAL( a[i], (i+1) * 10 );
    }
}

BOOST_AUTO_TEST_CASE( shuffle1024 ) {
    const int size = 1024;

    std::vector<int> a;
    for(int i = 0; i < size; ++i) {
        a.push_back((i+1) * 10);
    }

    for(int n = 0; n < 100; ++n) {
        std::random_shuffle(a.begin(), a.end());

        timsort(a.begin(), a.end(), &compare<int>);

        for(int i = 0; i < size; ++i) {
            BOOST_CHECK_EQUAL( a[i], (i+1) * 10 );
        }
    }
}
<commit_msg>Tests with c array<commit_after>#include <iostream>
#include <vector>
#include <algorithm>

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE TimSortTest
#include <boost/test/unit_test.hpp>

#include "timsort.hpp"

template<typename T>
int compare(T x, T y) {
    if(x == y) {
        return 0;
    }
    else if(x < y) {
        return -1;
    }
    else {
        return 1;
    }
}

BOOST_AUTO_TEST_CASE( simple10 ) {
    std::vector<int> a;
    a.push_back(60);
    a.push_back(50);
    a.push_back( 1);
    a.push_back(40);
    a.push_back(80);
    a.push_back(20);
    a.push_back(30);
    a.push_back(70);
    a.push_back(10);
    a.push_back(90);

    timsort(a.begin(), a.end(), &compare<int>);

    BOOST_CHECK_EQUAL( a[0],  1 );
    BOOST_CHECK_EQUAL( a[1], 10 );
    BOOST_CHECK_EQUAL( a[2], 20 );
    BOOST_CHECK_EQUAL( a[3], 30 );
    BOOST_CHECK_EQUAL( a[4], 40 );
    BOOST_CHECK_EQUAL( a[5], 50 );
    BOOST_CHECK_EQUAL( a[6], 60 );
    BOOST_CHECK_EQUAL( a[7], 70 );
    BOOST_CHECK_EQUAL( a[8], 80 );
    BOOST_CHECK_EQUAL( a[9], 90 );

    std::reverse(a.begin(), a.end());

    timsort(a.begin(), a.end(), &compare<int>);

    BOOST_CHECK_EQUAL( a[0],  1 );
    BOOST_CHECK_EQUAL( a[1], 10 );
    BOOST_CHECK_EQUAL( a[2], 20 );
    BOOST_CHECK_EQUAL( a[3], 30 );
    BOOST_CHECK_EQUAL( a[4], 40 );
    BOOST_CHECK_EQUAL( a[5], 50 );
    BOOST_CHECK_EQUAL( a[6], 60 );
    BOOST_CHECK_EQUAL( a[7], 70 );
    BOOST_CHECK_EQUAL( a[8], 80 );
    BOOST_CHECK_EQUAL( a[9], 90 );
}

BOOST_AUTO_TEST_CASE( shuffle30 ) {
    const int size = 30;

    std::vector<int> a;
    for(int i = 0; i < size; ++i) {
        a.push_back((i+1) * 10);
    }
    std::random_shuffle(a.begin(), a.end());

    timsort(a.begin(), a.end(), &compare<int>);

    for(int i = 0; i < size; ++i) {
        BOOST_CHECK_EQUAL( a[i], (i+1) * 10 );
    }
}

BOOST_AUTO_TEST_CASE( shuffle31 ) {
    const int size = 31;

    std::vector<int> a;
    for(int i = 0; i < size; ++i) {
        a.push_back((i+1) * 10);
    }
    std::random_shuffle(a.begin(), a.end());

    timsort(a.begin(), a.end(), &compare<int>);

    for(int i = 0; i < size; ++i) {
        BOOST_CHECK_EQUAL( a[i], (i+1) * 10 );
    }
}

BOOST_AUTO_TEST_CASE( shuffle32 ) {
    const int size = 32;

    std::vector<int> a;
    for(int i = 0; i < size; ++i) {
        a.push_back((i+1) * 10);
    }
    std::random_shuffle(a.begin(), a.end());

    timsort(a.begin(), a.end(), &compare<int>);

    for(int i = 0; i < size; ++i) {
        BOOST_CHECK_EQUAL( a[i], (i+1) * 10 );
    }
}

BOOST_AUTO_TEST_CASE( shuffle128 ) {
    const int size = 128;

    std::vector<int> a;
    for(int i = 0; i < size; ++i) {
        a.push_back((i+1) * 10);
    }
    std::random_shuffle(a.begin(), a.end());

    timsort(a.begin(), a.end(), &compare<int>);

    for(int i = 0; i < size; ++i) {
        BOOST_CHECK_EQUAL( a[i], (i+1) * 10 );
    }
}

BOOST_AUTO_TEST_CASE( shuffle1024 ) {
    const int size = 1024;

    std::vector<int> a;
    for(int i = 0; i < size; ++i) {
        a.push_back((i+1) * 10);
    }

    for(int n = 0; n < 100; ++n) {
        std::random_shuffle(a.begin(), a.end());

        timsort(a.begin(), a.end(), &compare<int>);

        for(int i = 0; i < size; ++i) {
            BOOST_CHECK_EQUAL( a[i], (i+1) * 10 );
        }
    }
}

BOOST_AUTO_TEST_CASE( c_array ) {
    int a[] = { 7, 1, 5, 3, 9 };

    timsort(a, a + sizeof(a) / sizeof(int), &compare<int>);

    BOOST_CHECK_EQUAL(a[0], 1);
    BOOST_CHECK_EQUAL(a[1], 3);
    BOOST_CHECK_EQUAL(a[2], 5);
    BOOST_CHECK_EQUAL(a[3], 7);
    BOOST_CHECK_EQUAL(a[4], 9);
}
<|endoftext|>


<commit_before>/* Copyright (c) 2010, Simeon Bird <spb41@cam.ac.uk>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
#define BOOST_TEST_DYN_LINK

/** \file
 * Test suite using boost::test*/
#define BOOST_TEST_MODULE NGENIC
#include "allvars.h"
#include "proto.h"
#include "part_data.hpp"
#include "cosmology.hpp"
#include <math.h>
#include <boost/test/unit_test.hpp>
#include <boost/test/test_tools.hpp>

#define FLOATS_NEAR_TO(x,y) \
        BOOST_CHECK_MESSAGE( fabs((x) - (y)) <= std::max<float>(fabs(x),fabs(y))/1e5,(x)<<" is not close to "<<(y))
#define FLOATS_CLOSE_TO(x,y) \
      BOOST_CHECK_MESSAGE( fabs((x) - (y)) <= std::max<float>(fabs(x),fabs(y))/1e3,(x)<<" is not close to "<<(y))

#ifdef PRINT_SPEC
BOOST_AUTO_TEST_CASE(check_print_spec)
{
        const int dims=5;
        float field[2*dims*dims*(dims/2+1)]={0};
        float pos[30];
        for(int i=0; i<30; i++)
                pos[i]=i/3.;
        fieldize(10, dims,field,10,10,pos,1);
        //Check off-diagonal elements are zero
        FLOATS_NEAR_TO(field[0],10.7638874);
        BOOST_CHECK_EQUAL(field[3],0);
        BOOST_CHECK_EQUAL(field[20],0);
        BOOST_CHECK_EQUAL(field[125],0);
        //Check on-diagonals
        FLOATS_NEAR_TO(field[124],2.08333);

}
#endif

// BOOST_AUTO_TEST_CASE(check_displacement_fields)
// {
//
// void displacement_fields(const int type, const int64_t NumPart, part_data& P, const int Nmesh, bool RayleighScatter);
// }

BOOST_AUTO_TEST_CASE(check_generate_header)
{
gadget_header generate_header(std::valarray<int64_t> & npart);

}

// BOOST_AUTO_TEST_CASE(check_displacement_read_out)
// {
// double displacement_read_out(float * Disp, const int order, const int64_t NumPart, part_data& P, const int Nmesh, const int axes);
//
//
// }

BOOST_AUTO_TEST_CASE(check_periodic_wrap)
{
    FLOATS_NEAR_TO(periodic_wrap(15000, 25000), 15000);
    FLOATS_NEAR_TO(periodic_wrap(65000, 25000), 15000);
    FLOATS_NEAR_TO(periodic_wrap(-10000, 25000), 15000);
    FLOATS_NEAR_TO(periodic_wrap(-60000, 25000), 15000);
}

// BOOST_AUTO_TEST_CASE(check_writing_data)
// {
// int64_t write_particle_data(GadgetWriter::GWriteSnap & snap, int type, part_data&  P, int64_t NumPart, int64_t FirstId);
//
// }

// BOOST_AUTO_TEST_CASE(check_power_spec_camb)
// {
// double PowerSpec_Tabulated(double k, int Type);
//
// }

class TestFermiDirac: public FermiDiracVel
{
    public:
       TestFermiDirac(int vel):FermiDiracVel(vel){}
       //For testing
       void reseed(int seed)
       {
           gsl_rng_set(g_rng, seed);
       }
       double get_fdv(int i)
       {
           if(i < LENGTH_FERMI_DIRAC_TABLE && i >= 0)
                return fermi_dirac_vel[i];
           return 0;
       }
       double get_fdvc(int i)
       {
           if(i < LENGTH_FERMI_DIRAC_TABLE && i >= 0)
                return fermi_dirac_cumprob[i];
           return 0;
       }
};

BOOST_AUTO_TEST_CASE(check_fermi_vel)
{
    //Check has units of velocity
    FLOATS_NEAR_TO(NU_V0(0, 1, 1e3), 100*NU_V0(0, 1, 1e5));
    //Check scales linearly with neutrino mass
    FLOATS_NEAR_TO(NU_V0(0, 0.1, 1e5), 10*NU_V0(0, 1, 1e5));
    //Check scales as z^3/2 (due to gadgets cosmological velocity unit)
    FLOATS_NEAR_TO(pow(0.5, 1.5)*NU_V0(1, 1, 1e5), NU_V0(0, 1, 1e5));
    //Check it is correct (roughly). This is
    //(4/11)^1/3* 2.7255* 1.00381* 8.61734e-5 * 2.99792e5/(M_nu/3)
    FLOATS_NEAR_TO(NU_V0(0,1, 1e5), 151.344);

    //Seed table with velocity of 100 km/s
    TestFermiDirac nuvels(100);
    nuvels.reseed(23);
    //Check that the probability table makes sense
    FLOATS_NEAR_TO(nuvels.get_fdvc(0), 0);
    FLOATS_NEAR_TO(nuvels.get_fdvc(LENGTH_FERMI_DIRAC_TABLE-2), 1);
    //Check that the probability table makes sense
    FLOATS_NEAR_TO(nuvels.get_fdv(0), 0);
    FLOATS_NEAR_TO(nuvels.get_fdv(LENGTH_FERMI_DIRAC_TABLE-1), MAX_FERMI_DIRAC);
    FLOATS_NEAR_TO(nuvels.get_fdv(LENGTH_FERMI_DIRAC_TABLE/2), MAX_FERMI_DIRAC/2.*(1.+1./LENGTH_FERMI_DIRAC_TABLE));
    //Test getting the distribution
    FLOATS_NEAR_TO(nuvels.get_fermi_dirac_vel(0), 0);
    FLOATS_NEAR_TO(nuvels.get_fermi_dirac_vel(1), MAX_FERMI_DIRAC);
    //Number computed by python guessing
    FLOATS_CLOSE_TO(nuvels.get_fermi_dirac_vel(0.5), 2.839);
//     for(int i = 0; i < LENGTH_FERMI_DIRAC_TABLE/2; i+=20)
//         printf("%g %g\n", nuvels.get_fdv(i), nuvels.get_fdvc(i));
    //Remember to reseed the rng...
    float vel[3]={0,0,0};
    nuvels.add_thermal_speeds(vel);
    //Check scaling is linear
    //Remember to reseed the rng...
    TestFermiDirac nuvels2(200);
    nuvels2.reseed(23);
    float vel2[3]={0,0,0};
    nuvels2.add_thermal_speeds(vel2);
    FLOATS_NEAR_TO(sqrt(vel2[0]*vel2[0]+vel2[1]*vel2[1]+vel2[2]*vel2[2]), 2*sqrt(vel[0]*vel[0]+vel[1]*vel[1]+vel[2]*vel[2]));
    for(int i=0; i<3; i++)
        FLOATS_NEAR_TO(vel2[i], 2*vel[i]);
    //Check some statistical properties (max, min, mean)
    double mean=0;
    double max = 0;
    double min = 1e10;
    int nsample;
    for (nsample=0; nsample < 10000; nsample++)
    {
        float vvel[3]={0,0,0};
        nuvels.add_thermal_speeds(vvel);
        double v2 =sqrt(vvel[0]*vvel[0]+vvel[1]*vvel[1]+vvel[2]*vvel[2]);
        max = std::max(v2, max);
        min = std::min(v2, min);
        mean+=v2;
    }
    mean/=nsample;
    //Mean should be roughly 3*zeta(4)/zeta(3)*7/8/(3/4)* m_vamp
    FLOATS_CLOSE_TO(mean, 3*pow(M_PI,4)/90./1.202057*(7./8)/(3/4.)*100);
    BOOST_CHECK_MESSAGE( min > 0,min<<" less than zero");
    BOOST_CHECK_MESSAGE( max < MAX_FERMI_DIRAC*100,max<<" greater than upper bound");

}

BOOST_AUTO_TEST_CASE(check_cosmology)
{
    //Check that we get the right scalings for total matter domination.
    //Cosmology(double HubbleParam, double Omega, double OmegaLambda, double MNu, bool InvertedHierarchy): HubbleParam(HubbleParam), Omega(Omega), OmegaLambda(OmegaLambda), MNu(MNu),
    Cosmology cosmo(0.7, 1., 0., 0., false);
    FLOATS_CLOSE_TO(cosmo.Hubble(1), HUBBLE);
    FLOATS_CLOSE_TO(cosmo.Hubble(0.1), cosmo.Hubble(1)/pow(0.1,3/2.));
    FLOATS_CLOSE_TO(cosmo.growth(0.5)/cosmo.growth(1), 0.5);
    //Check that massless neutrinos work
    FLOATS_NEAR_TO(cosmo.OmegaNu(1), cosmo.OmegaR(1)*7./8.*pow(pow(4/11.,1/3.)*1.00381,4)*3);
    FLOATS_NEAR_TO(cosmo.OmegaNu(0.01), cosmo.OmegaNu(1)/pow(0.01,4));
    //Check that the velocity correction d ln D1/d lna is constant
    FLOATS_CLOSE_TO(1.0, cosmo.F_Omega(1.5));
    FLOATS_CLOSE_TO(1.0, cosmo.F_Omega(2));

    //More observationally relevant tests
    Cosmology cosmo2(0.7, 0.3, 0.7, 0., false);
    FLOATS_CLOSE_TO(0.01*log(cosmo2.growth(0.01+1e-3)/cosmo2.growth(0.01-1e-3))/2e-3, cosmo2.F_Omega(0.01));
}
<commit_msg>More tests<commit_after>/* Copyright (c) 2010, Simeon Bird <spb41@cam.ac.uk>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
#define BOOST_TEST_DYN_LINK

/** \file
 * Test suite using boost::test*/
#define BOOST_TEST_MODULE NGENIC
#include "allvars.h"
#include "proto.h"
#include "part_data.hpp"
#include "cosmology.hpp"
#include <math.h>
#include <boost/test/unit_test.hpp>
#include <boost/test/test_tools.hpp>

#define FLOATS_NEAR_TO(x,y) \
        BOOST_CHECK_MESSAGE( fabs((x) - (y)) <= std::max<float>(fabs(x),fabs(y))/1e5,(x)<<" is not close to "<<(y))
#define FLOATS_CLOSE_TO(x,y) \
      BOOST_CHECK_MESSAGE( fabs((x) - (y)) <= std::max<float>(fabs(x),fabs(y))/1e3,(x)<<" is not close to "<<(y))

#ifdef PRINT_SPEC
BOOST_AUTO_TEST_CASE(check_print_spec)
{
        const int dims=5;
        float field[2*dims*dims*(dims/2+1)]={0};
        float pos[30];
        for(int i=0; i<30; i++)
                pos[i]=i/3.;
        fieldize(10, dims,field,10,10,pos,1);
        //Check off-diagonal elements are zero
        FLOATS_NEAR_TO(field[0],10.7638874);
        BOOST_CHECK_EQUAL(field[3],0);
        BOOST_CHECK_EQUAL(field[20],0);
        BOOST_CHECK_EQUAL(field[125],0);
        //Check on-diagonals
        FLOATS_NEAR_TO(field[124],2.08333);

}
#endif

// BOOST_AUTO_TEST_CASE(check_displacement_fields)
// {
//
// void displacement_fields(const int type, const int64_t NumPart, part_data& P, const int Nmesh, bool RayleighScatter);
// }

BOOST_AUTO_TEST_CASE(check_generate_header)
{
gadget_header generate_header(std::valarray<int64_t> & npart);

}

// BOOST_AUTO_TEST_CASE(check_displacement_read_out)
// {
// double displacement_read_out(float * Disp, const int order, const int64_t NumPart, part_data& P, const int Nmesh, const int axes);
//
//
// }

BOOST_AUTO_TEST_CASE(check_periodic_wrap)
{
    FLOATS_NEAR_TO(periodic_wrap(15000, 25000), 15000);
    FLOATS_NEAR_TO(periodic_wrap(65000, 25000), 15000);
    FLOATS_NEAR_TO(periodic_wrap(-10000, 25000), 15000);
    FLOATS_NEAR_TO(periodic_wrap(-60000, 25000), 15000);
}

// BOOST_AUTO_TEST_CASE(check_writing_data)
// {
// int64_t write_particle_data(GadgetWriter::GWriteSnap & snap, int type, part_data&  P, int64_t NumPart, int64_t FirstId);
//
// }

// BOOST_AUTO_TEST_CASE(check_power_spec_camb)
// {
// double PowerSpec_Tabulated(double k, int Type);
//
// }

class TestFermiDirac: public FermiDiracVel
{
    public:
       TestFermiDirac(int vel):FermiDiracVel(vel){}
       //For testing
       void reseed(int seed)
       {
           gsl_rng_set(g_rng, seed);
       }
       double get_fdv(int i)
       {
           if(i < LENGTH_FERMI_DIRAC_TABLE && i >= 0)
                return fermi_dirac_vel[i];
           return 0;
       }
       double get_fdvc(int i)
       {
           if(i < LENGTH_FERMI_DIRAC_TABLE && i >= 0)
                return fermi_dirac_cumprob[i];
           return 0;
       }
};

BOOST_AUTO_TEST_CASE(check_fermi_vel)
{
    //Check has units of velocity
    FLOATS_NEAR_TO(NU_V0(0, 1, 1e3), 100*NU_V0(0, 1, 1e5));
    //Check scales linearly with neutrino mass
    FLOATS_NEAR_TO(NU_V0(0, 0.1, 1e5), 10*NU_V0(0, 1, 1e5));
    //Check scales as z^3/2 (due to gadgets cosmological velocity unit)
    FLOATS_NEAR_TO(pow(0.5, 1.5)*NU_V0(1, 1, 1e5), NU_V0(0, 1, 1e5));
    //Check it is correct (roughly). This is
    //(4/11)^1/3* 2.7255* 1.00381* 8.61734e-5 * 2.99792e5/(M_nu/3)
    FLOATS_NEAR_TO(NU_V0(0,1, 1e5), 151.344);

    //Seed table with velocity of 100 km/s
    TestFermiDirac nuvels(100);
    nuvels.reseed(23);
    //Check that the probability table makes sense
    FLOATS_NEAR_TO(nuvels.get_fdvc(0), 0);
    FLOATS_NEAR_TO(nuvels.get_fdvc(LENGTH_FERMI_DIRAC_TABLE-2), 1);
    //Check that the probability table makes sense
    FLOATS_NEAR_TO(nuvels.get_fdv(0), 0);
    FLOATS_NEAR_TO(nuvels.get_fdv(LENGTH_FERMI_DIRAC_TABLE-1), MAX_FERMI_DIRAC);
    FLOATS_NEAR_TO(nuvels.get_fdv(LENGTH_FERMI_DIRAC_TABLE/2), MAX_FERMI_DIRAC/2.*(1.+1./LENGTH_FERMI_DIRAC_TABLE));
    //Test getting the distribution
    FLOATS_NEAR_TO(nuvels.get_fermi_dirac_vel(0), 0);
    FLOATS_NEAR_TO(nuvels.get_fermi_dirac_vel(1), MAX_FERMI_DIRAC);
    //Number computed by python guessing
    FLOATS_CLOSE_TO(nuvels.get_fermi_dirac_vel(0.5), 2.839);
//     for(int i = 0; i < LENGTH_FERMI_DIRAC_TABLE/2; i+=20)
//         printf("%g %g\n", nuvels.get_fdv(i), nuvels.get_fdvc(i));
    //Remember to reseed the rng...
    float vel[3]={0,0,0};
    nuvels.add_thermal_speeds(vel);
    //Check scaling is linear
    //Remember to reseed the rng...
    TestFermiDirac nuvels2(200);
    nuvels2.reseed(23);
    float vel2[3]={0,0,0};
    nuvels2.add_thermal_speeds(vel2);
    FLOATS_NEAR_TO(sqrt(vel2[0]*vel2[0]+vel2[1]*vel2[1]+vel2[2]*vel2[2]), 2*sqrt(vel[0]*vel[0]+vel[1]*vel[1]+vel[2]*vel[2]));
    for(int i=0; i<3; i++)
        FLOATS_NEAR_TO(vel2[i], 2*vel[i]);
    //Check some statistical properties (max, min, mean)
    double mean=0;
    double max = 0;
    double min = 1e10;
    int nsample;
    for (nsample=0; nsample < 10000; nsample++)
    {
        float vvel[3]={0,0,0};
        nuvels.add_thermal_speeds(vvel);
        double v2 =sqrt(vvel[0]*vvel[0]+vvel[1]*vvel[1]+vvel[2]*vvel[2]);
        max = std::max(v2, max);
        min = std::min(v2, min);
        mean+=v2;
    }
    mean/=nsample;
    //Mean should be roughly 3*zeta(4)/zeta(3)*7/8/(3/4)* m_vamp
    FLOATS_CLOSE_TO(mean, 3*pow(M_PI,4)/90./1.202057*(7./8)/(3/4.)*100);
    BOOST_CHECK_MESSAGE( min > 0,min<<" less than zero");
    BOOST_CHECK_MESSAGE( max < MAX_FERMI_DIRAC*100,max<<" greater than upper bound");

}

BOOST_AUTO_TEST_CASE(check_cosmology)
{
    //Check that we get the right scalings for total matter domination.
    //Cosmology(double HubbleParam, double Omega, double OmegaLambda, double MNu, bool InvertedHierarchy): HubbleParam(HubbleParam), Omega(Omega), OmegaLambda(OmegaLambda), MNu(MNu),
    Cosmology cosmo(0.7, 1., 0., 0., false);
    FLOATS_CLOSE_TO(cosmo.Hubble(1), HUBBLE);
    FLOATS_CLOSE_TO(cosmo.Hubble(0.1), cosmo.Hubble(1)/pow(0.1,3/2.));
    FLOATS_CLOSE_TO(cosmo.growth(0.5)/cosmo.growth(1), 0.5);
    //Check that massless neutrinos work
    FLOATS_NEAR_TO(cosmo.OmegaNu(1), cosmo.OmegaR(1)*7./8.*pow(pow(4/11.,1/3.)*1.00381,4)*3);
    FLOATS_NEAR_TO(cosmo.OmegaNu(0.01), cosmo.OmegaNu(1)/pow(0.01,4));
    //Check that the velocity correction d ln D1/d lna is constant
    FLOATS_CLOSE_TO(1.0, cosmo.F_Omega(1.5));
    FLOATS_CLOSE_TO(1.0, cosmo.F_Omega(2));

    //More observationally relevant tests
    Cosmology cosmo2(0.7, 0.3, 0.7, 0., false);
    FLOATS_CLOSE_TO(0.01*log(cosmo2.growth(0.01+1e-5)/cosmo2.growth(0.01-1e-5))/2e-5, cosmo2.F_Omega(0.01));

    //Massive neutrinos
    Cosmology nuc(0.7, 0.3, 0.7, 1.0, false);
    FLOATS_CLOSE_TO(0.01*log(nuc.growth(0.01+1e-5)/nuc.growth(0.01-1e-5))/2e-5, nuc.F_Omega(0.01));
    FLOATS_CLOSE_TO(nuc.OmegaNu(0.5), nuc.OmegaNu(1.)/0.125);
    FLOATS_CLOSE_TO(nuc.OmegaNu(0.00001)*pow(0.00001,4), nuc.OmegaNu(0.00002)*pow(0.00002,4));
}
<|endoftext|>