<commit_before>#include "gvki/Logger.h"
#include "gvki/PathSeperator.h"
#include <cstdlib>
#include <cstdio>
#include <cassert>
#include <errno.h>
#include <iostream>
#include <iomanip>
#include <sstream>
#include "string.h"
#include "gvki/Debug.h"

#include <sys/stat.h>

#ifndef _WIN32

#include <dirent.h>
#include <unistd.h>
#define MKDIR_FAILS(d)     (mkdir(d, 0770) != 0)
#define DIR_ALREADY_EXISTS (errno == EEXIST)

static void checkDirectoryExists(const char* dirName) {
    DIR* dh = opendir(dirName);
    if (dh != NULL)
    {
        closedir(dh);
        return;
    }
    ERROR_MSG(strerror(errno) << ". Directory was :" << dirName);
    exit(1);
}

#else

#include <inttypes.h>
#include <Windows.h>
#define MKDIR_FAILS(d)     (CreateDirectory(ss.str().c_str(), NULL) == 0)
#define DIR_ALREADY_EXISTS (GetLastError() == ERROR_ALREADY_EXISTS)

static void checkDirectoryExists(const char* dirName) {
    DWORD ftyp = GetFileAttributesA(dirName);
    if ((ftyp != INVALID_FILE_ATTRIBUTES) && ftyp & FILE_ATTRIBUTE_DIRECTORY)
        return;
    ERROR_MSG(strerror(errno) << ". Directory was :" << dirName);
    exit(1);
}

#endif

using namespace std;
using namespace gvki;

// Maximum number of files or directories
// that can be created
static const int maxFiles = 10000;

Logger& Logger::Singleton()
{
    static Logger l;
    return l;
}

Logger::Logger()
{
    int count = 0;
    bool success= false;

    // FIXME: Reading from the environment probably doesn't belong in here
    // but it makes implementing the singleton a lot easier
    std::string directoryPrefix;

    const char* envTemp = getenv("GVKI_ROOT");
    if (envTemp)
    {
        DEBUG_MSG("Using GVKI_ROOT value as destination for directories");

        checkDirectoryExists(envTemp);

        directoryPrefix = envTemp;

    }
    else
    {
        // Use the current working directory
        DEBUG_MSG("Using current working directory as destination for directories");

        // FIXME: Hard-coding this size is gross
        #define MAX_DIR_LENGTH 1024

#ifndef _WIN32
        char cwdArray[MAX_DIR_LENGTH];
        char* cwdResult = getcwd(cwdArray, sizeof(cwdArray)/sizeof(char));
        if (!cwdResult)
#else
        char cwdResult[MAX_DIR_LENGTH];
        if (GetCurrentDirectory(MAX_DIR_LENGTH, cwdResult) == 0)
#endif
        {
            ERROR_MSG(strerror(errno) << ". Could not read the current working directory");
            exit(1);
        }
        else
            directoryPrefix = cwdResult;
    }
    directoryPrefix += PATH_SEP "gvki";
    DEBUG_MSG("Directory prefix is \"" << directoryPrefix << "\"");

    // Keep trying a directoryPrefix name with a number as suffix
    // until we find an available one or we exhaust the maximum
    // allowed number
    while (count < maxFiles)
    {
        stringstream ss;
        ss <<  directoryPrefix << "-" << count;
        ++count;

        // Make the directoryPrefix
        if (MKDIR_FAILS(ss.str().c_str()))
        {
            if (!DIR_ALREADY_EXISTS)
            {
                ERROR_MSG(strerror(errno) << ". Directory was :" << directoryPrefix);
                exit(1);
            }

            // It already exists, try again
            continue;
        }

        this->directory = ss.str();
        success = true;
        break;
    }

    if (!success)
    {
        ERROR_MSG("Exhausted available directory names or couldn't create any");
        exit(1);
    }

    DEBUG_MSG("Directory used for logging is \"" << this->directory << "\"");

    openLog();
}

void Logger::openLog()
{
    // FIXME: We should use mkstemp() or something
    std::stringstream ss;
    ss << directory << PATH_SEP << "log.json";
    output = new std::ofstream(ss.str().c_str(), std::ofstream::out | std::ofstream::ate);

    if (! output->good())
    {
        ERROR_MSG("Failed to create file (" << ss.str() <<  ") to write log to");
        exit(1);
    }

    // Start of JSON array
    *output << "[" << std::endl;
}

void Logger::closeLog()
{
    // End of JSON array
    *output << std::endl << "]" << std::endl;
    output->close();
}

Logger::~Logger()
{
    closeLog();
    delete output;
}

void Logger::dump(cl_kernel k)
{
    // Output JSON format defined by
    // http://multicore.doc.ic.ac.uk/tools/GPUVerify/docs/json_format.html
    KernelInfo& ki = kernels[k];

    static bool isFirst = true;

    if (!isFirst)
    {
        // Emit array element seperator
        // to seperate from previous dump
        *output << "," << endl;
    }
    isFirst = false;

    *output << "{" << endl << "\"language\": \"OpenCL\"," << endl;

    std::string kernelSourceFile = dumpKernelSource(ki);

    *output << "\"kernel_file\": \"" << kernelSourceFile << "\"," << endl;

    // FIXME: Teach GPUVerify how to handle non zero global_offset
    // FIXME: Document this json attribute!
    // Only emit global_offset if its non zero
    bool hasNonZeroGlobalOffset = false;
    for (int index=0; index < ki.globalWorkOffset.size() ; ++index)
    {
        if (ki.globalWorkOffset[index] != 0)
            hasNonZeroGlobalOffset = true;
    }
    if (hasNonZeroGlobalOffset)
    {
        *output << "\"global_offset\": ";
        printJSONArray(ki.globalWorkOffset);
        *output << "," << endl;
    }

    *output << "\"global_size\": ";
    printJSONArray(ki.globalWorkSize);
    *output << "," << endl;

    *output << "\"local_size\": ";
    printJSONArray(ki.localWorkSize);
    *output << "," << endl;

    assert( (ki.globalWorkOffset.size() == ki.globalWorkSize.size()) &&
            (ki.globalWorkSize.size() == ki.localWorkSize.size()) &&
            "dimension mismatch");

    *output << "\"entry_point\": \"" << ki.entryPointName << "\"";

    // entry_point might be the last entry is there were no kernel args
    if (ki.arguments.size() == 0)
        *output << endl;
    else
    {
        *output << "," << endl << "\"kernel_arguments\": [ " << endl;
        for (int argIndex=0; argIndex < ki.arguments.size() ; ++argIndex)
        {
            printJSONKernelArgumentInfo(ki.arguments[argIndex]);
            if (argIndex != (ki.arguments.size() -1))
                *output << "," << endl;
        }
        *output << endl << "]" << endl;
    }

    *output << "}";
}

void Logger::printJSONArray(std::vector<size_t>& array)
{
    *output << "[ ";
    for (int index=0; index < array.size(); ++index)
    {
        *output << array[index];

        if (index != (array.size() -1))
            *output << ", ";
    }
    *output << "]";
}

void Logger::printJSONKernelArgumentInfo(ArgInfo& ai)
{
    *output << "{";
    if (ai.argValue == NULL)
    {
        // NULL was passed to clSetKernelArg()
        // That implies its for unallocated memory
        *output << "\"type\": \"array\",";

        // If the arg is for local memory
        if (ai.argSize != sizeof(cl_mem) && ai.argSize != sizeof(cl_sampler))
        {
            // We assume this means this arguments is for local memory
            // where size actually means the sizeof the underlying buffer
            // rather than the size of the type.
            *output << "\"size\" : " << ai.argSize;
        }
        *output << "}";
        return;
    }

    // FIXME:
    // Eurgh... the spec says
    // ```
    // If the argument is a buffer object, the arg_value pointer can be NULL or
    // point to a NULL value in which case a NULL value will be used as the
    // value for the argument declared as a pointer to __global or __constant
    // memory in the kernel.  ```
    //
    // This makes it impossible (seeing as we don't know which address space
    // the arguments are in) to work out the argument type once derefencing the
    // pointer and finding it's equal zero because it could be a scalar constant
    // (of value 0) or it could be an unintialised array!

    // Hack:
    // It's hard to determine what type the argument is.
    // We can't dereference the void* to check if
    // it points to cl_mem we previously stored
    //
    // In some implementations cl_mem will be a pointer
    // which poses a risk if a scalar parameter of the same size
    // as the pointer type.
    if (ai.argSize == sizeof(cl_mem))
    {
       cl_mem mightBecl_mem = *((cl_mem*) ai.argValue);

       // We might be reading invalid data now
       if (buffers.count(mightBecl_mem) == 1)
       {
           // We're going to assume it's cl_mem that we saw before
           *output << "\"type\": \"array\",";
           BufferInfo& bi = buffers[mightBecl_mem];

           *output << "\"size\": " << bi.size << "}";
           return;
       }

    }

    // Hack: a similar hack of the image types
    if (ai.argSize == sizeof(cl_mem))
    {
       cl_mem mightBecl_mem = *((cl_mem*) ai.argValue);

       // We might be reading invalid data now
       if (images.count(mightBecl_mem) == 1)
       {
           // We're going to assume it's cl_mem that we saw before
           *output << "\"type\": \"image\"}";
           return;
       }

    }

    // Hack: a similar hack for the samplers
    if (ai.argSize == sizeof(cl_sampler))
    {
       cl_sampler mightBecl_sampler = *((cl_sampler*) ai.argValue);

       // We might be reading invalid data now
       if (samplers.count(mightBecl_sampler) == 1)
       {
           // We're going to assume it's cl_mem that we saw before
           *output << "\"type\": \"sampler\"}";
           return;
       }

    }

    // I guess it's scalar???
    *output << "\"type\": \"scalar\",";
    *output << " \"value\": \"0x";
    // Print the value as hex
    uint8_t* asByte = (uint8_t*) ai.argValue;
    // We assume the host is little endian so to print the values
    // we need to go through the array bytes backwards
    for (int byteIndex= ai.argSize -1; byteIndex >=0 ; --byteIndex)
    {
       *output << std::hex << std::setfill('0') << std::setw(2) << ( (unsigned) asByte[byteIndex]);
    }
    *output << "\"" << std::dec; //std::hex is sticky so switch back to decimal

    *output << "}";
    return;

}

static bool file_exists(std::string& name) {
	ifstream f(name.c_str());
	bool result = f.good();
	f.close();
	return result;
}

// Define the strict weak ordering over ProgramInfo instances
// Is this correct?
bool ProgramInfoCacheCompare::operator() (const ProgramInfo& lhs, const ProgramInfo& rhs) const
{
    // Use the fact that a strict-weak order is already defined over std::vector<>
    return lhs.sources < rhs.sources;
}

std::string Logger::dumpKernelSource(KernelInfo& ki)
{
    ProgramInfo& pi = programs[ki.program];

    // See if we can used a file that we already printed.
    // This avoid writing duplicate files.
    ProgCacheMapTy::iterator it = WrittenKernelFileCache.find(pi);
    if ( it != WrittenKernelFileCache.end() )
    {
        return it->second;
    }

    int count = 0;
    bool success = false;
    // FIXME: I really want a std::unique_ptr
    std::ofstream* kos = 0;
    std::string theKernelPath;
    while (count < maxFiles)
    {
        stringstream ss;
        ss << ki.entryPointName << "." << count << ".cl";

        ++count;

        std::string withDir = (directory + PATH_SEP) + ss.str();
        if (!file_exists(withDir))
        {
           kos = new std::ofstream(withDir.c_str());

           if (!kos->good())
           {
                kos->close();
                delete kos;
                continue;
           }

           success = true;
           theKernelPath = ss.str();
           break;
        }
    }

    if (!success)
    {
        ERROR_MSG("Failed to log kernel output");
        return std::string("FIXME");
    }

    // Write kernel source

    for (vector<string>::const_iterator b = pi.sources.begin(), e = pi.sources.end(); b != e; ++b)
    {
        *kos << *b;
    }

    // Urgh this is bad, need RAII!
    kos->close();
    delete kos;

    // Store in cache
    assert(WrittenKernelFileCache.count(pi) == 0 && "ProgramInfo already in cache!");
    WrittenKernelFileCache[pi] = theKernelPath;

    return theKernelPath;
}
<commit_msg>Added output of memory flags.<commit_after>#include "gvki/Logger.h"
#include "gvki/PathSeperator.h"
#include <cstdlib>
#include <cstdio>
#include <cassert>
#include <errno.h>
#include <iostream>
#include <iomanip>
#include <sstream>
#include "string.h"
#include "gvki/Debug.h"

#include <sys/stat.h>

#ifndef _WIN32

#include <dirent.h>
#include <unistd.h>
#define MKDIR_FAILS(d)     (mkdir(d, 0770) != 0)
#define DIR_ALREADY_EXISTS (errno == EEXIST)

static void checkDirectoryExists(const char* dirName) {
    DIR* dh = opendir(dirName);
    if (dh != NULL)
    {
        closedir(dh);
        return;
    }
    ERROR_MSG(strerror(errno) << ". Directory was :" << dirName);
    exit(1);
}

#else

#include <C:/prog/msinttypes/inttypes.h>
#include <Windows.h>
#define MKDIR_FAILS(d)     (CreateDirectory(ss.str().c_str(), NULL) == 0)
#define DIR_ALREADY_EXISTS (GetLastError() == ERROR_ALREADY_EXISTS)

static void checkDirectoryExists(const char* dirName) {
    DWORD ftyp = GetFileAttributesA(dirName);
    if ((ftyp != INVALID_FILE_ATTRIBUTES) && ftyp & FILE_ATTRIBUTE_DIRECTORY)
        return;
    ERROR_MSG(strerror(errno) << ". Directory was :" << dirName);
    exit(1);
}

#endif

using namespace std;
using namespace gvki;

// Maximum number of files or directories
// that can be created
static const int maxFiles = 10000;

Logger& Logger::Singleton()
{
    static Logger l;
    return l;
}

Logger::Logger()
{
    int count = 0;
    bool success= false;

    // FIXME: Reading from the environment probably doesn't belong in here
    // but it makes implementing the singleton a lot easier
    std::string directoryPrefix;

    const char* envTemp = getenv("GVKI_ROOT");
    if (envTemp)
    {
        DEBUG_MSG("Using GVKI_ROOT value as destination for directories");

        checkDirectoryExists(envTemp);

        directoryPrefix = envTemp;

    }
    else
    {
        // Use the current working directory
        DEBUG_MSG("Using current working directory as destination for directories");

        // FIXME: Hard-coding this size is gross
        #define MAX_DIR_LENGTH 1024

#ifndef _WIN32
        char cwdArray[MAX_DIR_LENGTH];
        char* cwdResult = getcwd(cwdArray, sizeof(cwdArray)/sizeof(char));
        if (!cwdResult)
#else
        char cwdResult[MAX_DIR_LENGTH];
        if (GetCurrentDirectory(MAX_DIR_LENGTH, cwdResult) == 0)
#endif
        {
            ERROR_MSG(strerror(errno) << ". Could not read the current working directory");
            exit(1);
        }
        else
            directoryPrefix = cwdResult;
    }
    directoryPrefix += PATH_SEP "gvki";
    DEBUG_MSG("Directory prefix is \"" << directoryPrefix << "\"");

    // Keep trying a directoryPrefix name with a number as suffix
    // until we find an available one or we exhaust the maximum
    // allowed number
    while (count < maxFiles)
    {
        stringstream ss;
        ss <<  directoryPrefix << "-" << count;
        ++count;

        // Make the directoryPrefix
        if (MKDIR_FAILS(ss.str().c_str()))
        {
            if (!DIR_ALREADY_EXISTS)
            {
                ERROR_MSG(strerror(errno) << ". Directory was :" << directoryPrefix);
                exit(1);
            }

            // It already exists, try again
            continue;
        }

        this->directory = ss.str();
        success = true;
        break;
    }

    if (!success)
    {
        ERROR_MSG("Exhausted available directory names or couldn't create any");
        exit(1);
    }

    DEBUG_MSG("Directory used for logging is \"" << this->directory << "\"");

    openLog();
}

void Logger::openLog()
{
    // FIXME: We should use mkstemp() or something
    std::stringstream ss;
    ss << directory << PATH_SEP << "log.json";
    output = new std::ofstream(ss.str().c_str(), std::ofstream::out | std::ofstream::ate);

    if (! output->good())
    {
        ERROR_MSG("Failed to create file (" << ss.str() <<  ") to write log to");
        exit(1);
    }

    // Start of JSON array
    *output << "[" << std::endl;
}

void Logger::closeLog()
{
    // End of JSON array
    *output << std::endl << "]" << std::endl;
    output->close();
}

Logger::~Logger()
{
    closeLog();
    delete output;
}

void Logger::dump(cl_kernel k)
{
    // Output JSON format defined by
    // http://multicore.doc.ic.ac.uk/tools/GPUVerify/docs/json_format.html
    KernelInfo& ki = kernels[k];

    static bool isFirst = true;

    if (!isFirst)
    {
        // Emit array element seperator
        // to seperate from previous dump
        *output << "," << endl;
    }
    isFirst = false;

    *output << "{" << endl << "\"language\": \"OpenCL\"," << endl;

    std::string kernelSourceFile = dumpKernelSource(ki);

    *output << "\"kernel_file\": \"" << kernelSourceFile << "\"," << endl;

    // FIXME: Teach GPUVerify how to handle non zero global_offset
    // FIXME: Document this json attribute!
    // Only emit global_offset if its non zero
    bool hasNonZeroGlobalOffset = false;
    for (int index=0; index < ki.globalWorkOffset.size() ; ++index)
    {
        if (ki.globalWorkOffset[index] != 0)
            hasNonZeroGlobalOffset = true;
    }
    if (hasNonZeroGlobalOffset)
    {
        *output << "\"global_offset\": ";
        printJSONArray(ki.globalWorkOffset);
        *output << "," << endl;
    }

    *output << "\"global_size\": ";
    printJSONArray(ki.globalWorkSize);
    *output << "," << endl;

    *output << "\"local_size\": ";
    printJSONArray(ki.localWorkSize);
    *output << "," << endl;

    assert( (ki.globalWorkOffset.size() == ki.globalWorkSize.size()) &&
            (ki.globalWorkSize.size() == ki.localWorkSize.size()) &&
            "dimension mismatch");

    *output << "\"entry_point\": \"" << ki.entryPointName << "\"";

    // entry_point might be the last entry is there were no kernel args
    if (ki.arguments.size() == 0)
        *output << endl;
    else
    {
        *output << "," << endl << "\"kernel_arguments\": [ " << endl;
        for (int argIndex=0; argIndex < ki.arguments.size() ; ++argIndex)
        {
            printJSONKernelArgumentInfo(ki.arguments[argIndex]);
            if (argIndex != (ki.arguments.size() -1))
                *output << "," << endl;
        }
        *output << endl << "]" << endl;
    }

    *output << "}";
}

void Logger::printJSONArray(std::vector<size_t>& array)
{
    *output << "[ ";
    for (int index=0; index < array.size(); ++index)
    {
        *output << array[index];

        if (index != (array.size() -1))
            *output << ", ";
    }
    *output << "]";
}

void Logger::printJSONKernelArgumentInfo(ArgInfo& ai)
{
    *output << "{";
    if (ai.argValue == NULL)
    {
        // NULL was passed to clSetKernelArg()
        // That implies its for unallocated memory
        *output << "\"type\": \"array\",";

        // If the arg is for local memory
        if (ai.argSize != sizeof(cl_mem) && ai.argSize != sizeof(cl_sampler))
        {
            // We assume this means this arguments is for local memory
            // where size actually means the sizeof the underlying buffer
            // rather than the size of the type.
            *output << "\"size\" : " << ai.argSize;
        }
        *output << "}";
        return;
    }

    // FIXME:
    // Eurgh... the spec says
    // ```
    // If the argument is a buffer object, the arg_value pointer can be NULL or
    // point to a NULL value in which case a NULL value will be used as the
    // value for the argument declared as a pointer to __global or __constant
    // memory in the kernel.  ```
    //
    // This makes it impossible (seeing as we don't know which address space
    // the arguments are in) to work out the argument type once derefencing the
    // pointer and finding it's equal zero because it could be a scalar constant
    // (of value 0) or it could be an unintialised array!

    // Hack:
    // It's hard to determine what type the argument is.
    // We can't dereference the void* to check if
    // it points to cl_mem we previously stored
    //
    // In some implementations cl_mem will be a pointer
    // which poses a risk if a scalar parameter of the same size
    // as the pointer type.
    if (ai.argSize == sizeof(cl_mem))
    {
       cl_mem mightBecl_mem = *((cl_mem*) ai.argValue);

       // We might be reading invalid data now
       if (buffers.count(mightBecl_mem) == 1)
       {
           // We're going to assume it's cl_mem that we saw before
           *output << "\"type\": \"array\", ";
           BufferInfo& bi = buffers[mightBecl_mem];

           *output << "\"size\": " << bi.size << ", ";

           *output << "\"flags\": \"";
           switch (bi.flags) {
             case CL_MEM_READ_ONLY:
               *output << "CL_MEM_READ_ONLY";
               break;
             case CL_MEM_WRITE_ONLY:
               *output << "CL_MEM_WRITE_ONLY";
               break;
             case CL_MEM_READ_WRITE:
               *output << "CL_MEM_READ_WRITE";
               break;
             default:
               *output << "UNKNOWN";
           }

           *output << "\"}";

           return;
       }

    }

    // Hack: a similar hack of the image types
    if (ai.argSize == sizeof(cl_mem))
    {
       cl_mem mightBecl_mem = *((cl_mem*) ai.argValue);

       // We might be reading invalid data now
       if (images.count(mightBecl_mem) == 1)
       {
           // We're going to assume it's cl_mem that we saw before
           *output << "\"type\": \"image\"}";
           return;
       }

    }

    // Hack: a similar hack for the samplers
    if (ai.argSize == sizeof(cl_sampler))
    {
       cl_sampler mightBecl_sampler = *((cl_sampler*) ai.argValue);

       // We might be reading invalid data now
       if (samplers.count(mightBecl_sampler) == 1)
       {
           // We're going to assume it's cl_mem that we saw before
           *output << "\"type\": \"sampler\"}";
           return;
       }

    }

    // I guess it's scalar???
    *output << "\"type\": \"scalar\",";
    *output << " \"value\": \"0x";
    // Print the value as hex
    uint8_t* asByte = (uint8_t*) ai.argValue;
    // We assume the host is little endian so to print the values
    // we need to go through the array bytes backwards
    for (int byteIndex= ai.argSize -1; byteIndex >=0 ; --byteIndex)
    {
       *output << std::hex << std::setfill('0') << std::setw(2) << ( (unsigned) asByte[byteIndex]);
    }
    *output << "\"" << std::dec; //std::hex is sticky so switch back to decimal

    *output << "}";
    return;

}

static bool file_exists(std::string& name) {
	ifstream f(name.c_str());
	bool result = f.good();
	f.close();
	return result;
}

// Define the strict weak ordering over ProgramInfo instances
// Is this correct?
bool ProgramInfoCacheCompare::operator() (const ProgramInfo& lhs, const ProgramInfo& rhs) const
{
    // Use the fact that a strict-weak order is already defined over std::vector<>
    return lhs.sources < rhs.sources;
}

std::string Logger::dumpKernelSource(KernelInfo& ki)
{
    ProgramInfo& pi = programs[ki.program];

    // See if we can used a file that we already printed.
    // This avoid writing duplicate files.
    ProgCacheMapTy::iterator it = WrittenKernelFileCache.find(pi);
    if ( it != WrittenKernelFileCache.end() )
    {
        return it->second;
    }

    int count = 0;
    bool success = false;
    // FIXME: I really want a std::unique_ptr
    std::ofstream* kos = 0;
    std::string theKernelPath;
    while (count < maxFiles)
    {
        stringstream ss;
        ss << ki.entryPointName << "." << count << ".cl";

        ++count;

        std::string withDir = (directory + PATH_SEP) + ss.str();
        if (!file_exists(withDir))
        {
           kos = new std::ofstream(withDir.c_str());

           if (!kos->good())
           {
                kos->close();
                delete kos;
                continue;
           }

           success = true;
           theKernelPath = ss.str();
           break;
        }
    }

    if (!success)
    {
        ERROR_MSG("Failed to log kernel output");
        return std::string("FIXME");
    }

    // Write kernel source

    for (vector<string>::const_iterator b = pi.sources.begin(), e = pi.sources.end(); b != e; ++b)
    {
        *kos << *b;
    }

    // Urgh this is bad, need RAII!
    kos->close();
    delete kos;

    // Store in cache
    assert(WrittenKernelFileCache.count(pi) == 0 && "ProgramInfo already in cache!");
    WrittenKernelFileCache[pi] = theKernelPath;

    return theKernelPath;
}
<|endoftext|>


<commit_before>// @(#)root/gpad:$Id$
// Author: Rene Brun  19/02/2007

/*************************************************************************
 * Copyright (C) 1995-2007, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "TView.h"
#include "TROOT.h"
#include "TPluginManager.h"

ClassImp(TView)

//____________________________________________________________________________
TView::TView(const TView& tv) :
   TObject(tv),
   TAttLine(tv)
{
   // Copy constructor.
}

//____________________________________________________________________________
TView *TView::CreateView(Int_t system, const Double_t *rmin, const Double_t *rmax)
{
   // Create a concrete default 3-d view via the plug-in manager

   TView *view = 0;
   TPluginHandler *h;
   if ((h = gROOT->GetPluginManager()->FindHandler("TView"))) {
      if (h->LoadPlugin() == -1)
         return 0;
      view = (TView*)h->ExecPlugin(3,system,rmin,rmax);
   }
   return view;
}
<commit_msg>- Add header<commit_after>// @(#)root/gpad:$Id$
// Author: Rene Brun  19/02/2007

/*************************************************************************
 * Copyright (C) 1995-2007, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "TView.h"
#include "TROOT.h"
#include "TPluginManager.h"

ClassImp(TView)

//______________________________________________________________________________
/* Begin_Html
See TView3D
End_Html */

//____________________________________________________________________________
TView::TView(const TView& tv) :
   TObject(tv),
   TAttLine(tv)
{
   // Copy constructor.
}

//____________________________________________________________________________
TView *TView::CreateView(Int_t system, const Double_t *rmin, const Double_t *rmax)
{
   // Create a concrete default 3-d view via the plug-in manager

   TView *view = 0;
   TPluginHandler *h;
   if ((h = gROOT->GetPluginManager()->FindHandler("TView"))) {
      if (h->LoadPlugin() == -1)
         return 0;
      view = (TView*)h->ExecPlugin(3,system,rmin,rmax);
   }
   return view;
}
<|endoftext|>


<commit_before>//-----------------------------------------------------------------------
// Copyright 2011 Ciaran McHale.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions.
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//----------------------------------------------------------------------

#include "platform.h"
#include <assert.h>
#include <stdlib.h>
#include <config4cpp/StringBuffer.h>
#ifdef P_STDIO_HAS_LIMITED_FDS
#	ifdef WIN32
		//--------
		// Windows does NOT suffer from this problem. However, we can
		// pretend it does so we can compile and test both versions of
		// the BufferedFileReader class on Windows.
		//--------
#		include <io.h>
#		include <fcntl.h>
#	else
#		include <sys/types.h>
#		include <sys/stat.h>
#		include <fcntl.h>
#	endif
#endif

namespace CONFIG4CPP_NAMESPACE {

bool
execCmd(const char * cmd, StringBuffer & output)
{
	StringBuffer			modifiedCmd;
	FILE *					pipe;
	int						ch;
	int						len;
	int						pcloseStatus;

	output.empty();

	//--------
	// Execute the command with its stderr and stdout merged together.
	// TO DO: the "modifiedCmd" below works on Linux and in a cmd
	// shell on Windows, but sometimes it does not work in a Cygwin
	// shell.
	//--------
	modifiedCmd << cmd << " 2>&1";
	//modifiedCmd << cmd;
	pipe = CONFIG4CPP_POPEN(modifiedCmd.c_str(), "r");
	if (!pipe) {
		output << "cannot execute '" << cmd << "': popen() failed";
		return false;
	}

	//--------
	// Read from the pipe and delete the final '\n', if any.
	//--------
	while ((ch = fgetc(pipe)) != EOF) {
		if (ch != '\r') {
			output.append((char)ch);
		}
	}
	len = output.length();
	if (len > 0 && output[len-1] == '\n') {
		output.deleteLastChar();
	}

	//--------
	// We're done. Return success (true) if the exit status of
	// the command was 0.
	//--------
	pcloseStatus = CONFIG4CPP_PCLOSE(pipe);
	return (pcloseStatus == 0);
}

#ifdef WIN32
//--------
// Windows version.
//--------
#include <windows.h>
bool
isCmdInDir(const char * cmd, const char * dir)
{
	StringBuffer			fileName;
	static const char *		extensions[] = { "", ".exe", ".bat", 0 };
	int						i;
	DWORD					fileAttr;

	for (i = 0; extensions[i] != 0; i++) {
		fileName = "";
		fileName << dir << "\\" << cmd << extensions[i];
		fileAttr = GetFileAttributes(fileName.c_str());
		if (fileAttr != 0xFFFFFFFF) {
			return true;
		}
	}
	return false;
}
#else
//--------
// UNIX version.
//--------
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
bool
isCmdInDir(const char * cmd, const char * dir)
{
	StringBuffer		fileName;
	struct stat			sb;

	fileName << dir << "/" << cmd;
	if (stat(fileName.c_str(), &sb) == 0) {
		return true;
	}
	return false;
}
#endif

#ifdef P_STDIO_HAS_LIMITED_FDS

BufferedFileReader::BufferedFileReader()
{
	m_fd = -1;
}

BufferedFileReader::~BufferedFileReader()
{
	if (m_fd != -1) {
		close();
	}
}

bool
BufferedFileReader::open(const char * fileName)
{
	assert(m_fd == -1);
	m_fd = ::open(fileName, O_RDONLY);
	m_bufIndex = 0;
	m_bufLen = 0;
	return (m_fd != -1);
}

bool
BufferedFileReader::close()
{
	int				result;

	assert(m_fd != -1);
	result = ::close(m_fd);
	if (result != -1) {
		m_fd = -1;
	}
	return (result != -1);
}

int
BufferedFileReader::getChar()
{
	int				size;
	int				result;

	assert(m_fd != -1);
	if (m_bufIndex == m_bufLen) {
		size = ::read(m_fd, m_buf, BUFFERED_FILE_READER_BUF_SIZE);
		m_bufIndex = 0;
		m_bufLen = size;
		if (size <= 0) {
			m_bufLen = 0;
			return EOF;
		}
	}
	assert(m_bufIndex < m_bufLen);
	result = m_buf[m_bufIndex];
	m_bufIndex++;
	return result;
}

#else

BufferedFileReader::BufferedFileReader()
{
	m_file = 0;
}

BufferedFileReader::~BufferedFileReader()
{
	if (m_file != 0) {
		fclose(m_file);
	}
}

bool
BufferedFileReader::open(const char * fileName)
{
	assert(m_file == 0);
	m_file = fopen(fileName, "r");
	return (m_file != 0);
}

bool
BufferedFileReader::close()
{
	int				status;

	status = fclose(m_file);
	return (status != -1);
}

int
BufferedFileReader::getChar()
{
	assert(m_file != 0);
	return fgetc(m_file);
}

#endif
} // namespace CONFIG4CPP_NAMESPACE
<commit_msg>Fixes.<commit_after>//-----------------------------------------------------------------------
// Copyright 2011 Ciaran McHale.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions.
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//----------------------------------------------------------------------

#include "platform.h"
#include <assert.h>
#include <stdlib.h>
#include <config4cpp/StringBuffer.h>
#ifdef P_STDIO_HAS_LIMITED_FDS
#	ifdef WIN32
		//--------
		// Windows does NOT suffer from this problem. However, we can
		// pretend it does so we can compile and test both versions of
		// the BufferedFileReader class on Windows.
		//--------
#		include <io.h>
#		include <fcntl.h>
#	else
#		include <sys/types.h>
#		include <sys/stat.h>
#		include <fcntl.h>
#	endif
#endif

namespace CONFIG4CPP_NAMESPACE {

bool
execCmd(const char * cmd, StringBuffer & output)
{
	StringBuffer			modifiedCmd;
	FILE *					pipe;
	int						ch;
	int						len;
	int						pcloseStatus;

	output.empty();

	//--------
	// Execute the command with its stderr and stdout merged together.
	// TO DO: the "modifiedCmd" below works on Linux and in a cmd
	// shell on Windows, but sometimes it does not work in a Cygwin
	// shell.
	//--------
	modifiedCmd << cmd << " 2>&1";
	//modifiedCmd << cmd;
	pipe = CONFIG4CPP_POPEN(modifiedCmd.c_str(), "r");
	if (!pipe) {
		output << "cannot execute '" << cmd << "': popen() failed";
		return false;
	}

	//--------
	// Read from the pipe and delete the final '\n', if any.
	//--------
	while ((ch = fgetc(pipe)) != EOF) {
		if (ch != '\r') {
			output.append((char)ch);
		}
	}
	len = output.length();
	if (len > 0 && output[len-1] == '\n') {
		output.deleteLastChar();
	}

	//--------
	// We're done. Return success (true) if the exit status of
	// the command was 0.
	//--------
	pcloseStatus = CONFIG4CPP_PCLOSE(pipe);
	return (pcloseStatus == 0);
}

#ifdef WIN32
//--------
// Windows version.
//--------
#include <windows.h>
bool
isCmdInDir(const char * cmd, const char * dir)
{
	StringBuffer			fileName;
	static const char *		extensions[] = { "", ".exe", ".bat", 0 };
	int						i;
	DWORD					fileAttr;

	for (i = 0; extensions[i] != 0; i++) {
		fileName = "";
		fileName << dir << "\\" << cmd << extensions[i];
		fileAttr = GetFileAttributes(fileName.c_str());
		if (fileAttr != 0xFFFFFFFF) {
			return true;
		}
	}
	return false;
}
#else
//--------
// UNIX version.
//--------
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
bool
isCmdInDir(const char * cmd, const char * dir)
{
	StringBuffer		fileName;
	struct stat			sb;

	fileName << dir << "/" << cmd;
	if (stat(fileName.c_str(), &sb) == 0) {
		return true;
	}
	return false;
}
#endif

#ifdef P_STDIO_HAS_LIMITED_FDS

BufferedFileReader::BufferedFileReader() : m_fd(-1), m_buf(nullptr), m_bufIndex(0), m_bufLen(0)
{
}

BufferedFileReader::~BufferedFileReader()
{
	if (m_fd != -1) {
		close();
	}
}

bool
BufferedFileReader::open(const char * fileName)
{
	assert(m_fd == -1);
	m_fd = ::open(fileName, O_RDONLY);
	m_bufIndex = 0;
	m_bufLen = 0;
	return (m_fd != -1);
}

bool
BufferedFileReader::close()
{
	int				result;

	assert(m_fd != -1);
	result = ::close(m_fd);
	if (result != -1) {
		m_fd = -1;
	}
	return (result != -1);
}

int
BufferedFileReader::getChar()
{
	int				result;

	assert(m_fd != -1);
	if (m_bufIndex == m_bufLen) {
		int size = ::read(m_fd, m_buf, BUFFERED_FILE_READER_BUF_SIZE);
		m_bufIndex = 0;
		m_bufLen = size;
		if (size <= 0) {
			m_bufLen = 0;
			return EOF;
		}
	}
	assert(m_bufIndex < m_bufLen);
	result = m_buf[m_bufIndex];
	m_bufIndex++;
	return result;
}

#else

BufferedFileReader::BufferedFileReader()
{
	m_file = 0;
}

BufferedFileReader::~BufferedFileReader()
{
	if (m_file != 0) {
		fclose(m_file);
	}
}

bool
BufferedFileReader::open(const char * fileName)
{
	assert(m_file == 0);
	m_file = fopen(fileName, "r");
	return (m_file != 0);
}

bool
BufferedFileReader::close()
{
	int				status;

	status = fclose(m_file);
	return (status != -1);
}

int
BufferedFileReader::getChar()
{
	assert(m_file != 0);
	return fgetc(m_file);
}

#endif
} // namespace CONFIG4CPP_NAMESPACE
<|endoftext|>


<commit_before>#include <ros/ros.h>

#include <moveit/move_group_interface/move_group.h>
#include <moveit/planning_scene_interface/planning_scene_interface.h>
#include <moveit/planning_scene/planning_scene.h>

#include <moveit_msgs/DisplayRobotState.h>
#include <moveit_msgs/DisplayTrajectory.h>

#include <moveit/warehouse/planning_scene_storage.h>

#include <boost/program_options.hpp>

int main(int argc, char** argv)
{
  ros::init(argc, argv, "moveit_recorder");
  ros::NodeHandle node_handle;
  ros::AsyncSpinner spinner(1);
  spinner.start();

  sleep(20); // to let RVIZ come up

  boost::program_options::options_description desc;
  desc.add_options()
    ("help", "Show help message")
    ("host", boost::program_options::value<std::string>(), "Host for the MongoDB.")
    ("port", boost::program_options::value<std::size_t>(), "Port for the MongoDB.");

  boost::program_options::variables_map vm;
  boost::program_options::parsed_options po = boost::program_options::parse_command_line(argc, argv, desc);
  boost::program_options::store(po, vm);
  boost::program_options::notify(vm);

  if (vm.count("help") || argc == 1) // show help if no parameters passed
  {
    std::cout << desc << std::endl;
    return 1;
  }
  try
  {
    //connect to the DB
    std::string host = vm.count("host") ? vm["host"].as<std::string>() : "";
    size_t port = vm.count("port") ? vm["port"].as<std::size_t>() : 0;
    moveit_warehouse::PlanningSceneStorage pss(host, port);

    ROS_INFO("Connected to Warehouse DB at host (%s) and port (%d)", host.c_str(), (int)port);

    ros::Publisher display_publisher = node_handle.advertise<moveit_msgs::DisplayTrajectory>("/move_group/display_planned_path", 1, true);
    moveit_msgs::DisplayTrajectory display_trajectory;

    //ask the warehouse for the scene
    std::vector<std::string> ps_names;
    pss.getPlanningSceneNames( ps_names );
    ros::Publisher ps_pub = node_handle.advertise<moveit_msgs::PlanningScene>("planning_scene", 1);

    std::vector<std::string>::iterator scene = ps_names.begin();
    for(; scene!=ps_names.end(); ++scene)
    {
      moveit_warehouse::PlanningSceneWithMetadata pswm;
      pss.getPlanningScene(pswm, *scene);

      // visualize the scene
      // apparently with metadata it extends it
      moveit_msgs::PlanningScene ps_msg = static_cast<const moveit_msgs::PlanningScene&>(*pswm);
      ps_pub.publish(ps_msg);

      //get query list
      std::vector<std::string> pq_names;
      pss.getPlanningQueriesNames( pq_names, *scene);

      std::string first_query = pq_names[0];

      ROS_INFO("%d available queries", (int)pq_names.size());

      //get trajectory list
      std::vector<moveit_warehouse::RobotTrajectoryWithMetadata> planning_results;
      pss.getPlanningResults(planning_results, *scene, first_query);

      ROS_INFO("Loaded %d trajectories for query %s", (int)planning_results.size(), first_query.c_str());

      //animate the first trajectory
      moveit_msgs::RobotTrajectory rt_msg = static_cast<const moveit_msgs::RobotTrajectory&>(*(planning_results[0]));

      //get the start point
      moveit_warehouse::MotionPlanRequestWithMetadata planning_query;
      pss.getPlanningQuery(planning_query, *scene, first_query);
      moveit_msgs::MotionPlanRequest mpr = static_cast<const moveit_msgs::MotionPlanRequest&>(*planning_query);

      //publish
      display_trajectory.trajectory_start = mpr.start_state;
      display_trajectory.trajectory.push_back(rt_msg);
      display_publisher.publish(display_trajectory);
      sleep(5.0);
    }

    //std::vector<std::string> files = boost::program_options::collect_unrecognized(po.options, boost::program_options::include_positional);
  }
  catch(mongo_ros::DbConnectException &ex)
  {
    ROS_ERROR_STREAM("Unable to connect to warehouse. If you just created the database, it could take a while for initial setup. Please try to run the benchmark again."
        << std::endl << ex.what());
  }

  ROS_INFO("Successfully performed trajectory playback");
  ros::shutdown();
  return 0;
}
<commit_msg>need to figure out why there are zero trajectories being recalled from the queries ...<commit_after>#include <ros/ros.h>

#include <moveit/move_group_interface/move_group.h>
#include <moveit/planning_scene_interface/planning_scene_interface.h>
#include <moveit/planning_scene/planning_scene.h>

#include <moveit_msgs/DisplayRobotState.h>
#include <moveit_msgs/DisplayTrajectory.h>

#include <moveit/warehouse/planning_scene_storage.h>

#include <boost/program_options.hpp>

int main(int argc, char** argv)
{
  ros::init(argc, argv, "moveit_recorder");
  ros::NodeHandle node_handle;
  ros::AsyncSpinner spinner(1);
  spinner.start();

  sleep(20); // to let RVIZ come up

  boost::program_options::options_description desc;
  desc.add_options()
    ("help", "Show help message")
    ("host", boost::program_options::value<std::string>(), "Host for the MongoDB.")
    ("port", boost::program_options::value<std::size_t>(), "Port for the MongoDB.");

  boost::program_options::variables_map vm;
  boost::program_options::parsed_options po = boost::program_options::parse_command_line(argc, argv, desc);
  boost::program_options::store(po, vm);
  boost::program_options::notify(vm);

  if (vm.count("help") || argc == 1) // show help if no parameters passed
  {
    std::cout << desc << std::endl;
    return 1;
  }
  try
  {
    //connect to the DB
    std::string host = vm.count("host") ? vm["host"].as<std::string>() : "";
    size_t port = vm.count("port") ? vm["port"].as<std::size_t>() : 0;
    moveit_warehouse::PlanningSceneStorage pss(host, port);

    ROS_INFO("Connected to Warehouse DB at host (%s) and port (%d)", host.c_str(), (int)port);

    ros::Publisher display_publisher = node_handle.advertise<moveit_msgs::DisplayTrajectory>("/move_group/display_planned_path", 1, true);
    moveit_msgs::DisplayTrajectory display_trajectory;

    //ask the warehouse for the scene
    std::vector<std::string> ps_names;
    pss.getPlanningSceneNames( ps_names );
    ros::Publisher ps_pub = node_handle.advertise<moveit_msgs::PlanningScene>("planning_scene", 1);

    std::vector<std::string>::iterator scene = ps_names.begin();
    for(; scene!=ps_names.end(); ++scene)
    {
      moveit_warehouse::PlanningSceneWithMetadata pswm;
      pss.getPlanningScene(pswm, *scene);

      // visualize the scene
      // apparently with metadata it extends it
      moveit_msgs::PlanningScene ps_msg = static_cast<const moveit_msgs::PlanningScene&>(*pswm);
      ps_pub.publish(ps_msg);

      //get query list
      std::vector<std::string> pq_names;
      pss.getPlanningQueriesNames( pq_names, *scene);

      std::string first_query = pq_names.at(0);

      std::cout << pq_names.at(0) << std::endl;
      std::cout << pq_names.at(1) << std::endl;
      std::cout << pq_names.at(2) << std::endl;

      ROS_INFO("%d available queries", (int)pq_names.size());

      //get trajectory list
      std::vector<moveit_warehouse::RobotTrajectoryWithMetadata> planning_results;
      pss.getPlanningResults(planning_results, *scene, first_query);

      ROS_INFO("Loaded %d trajectories for query %s", (int)planning_results.size(), first_query.c_str());

      //TODO WHY IS THIS NOT LOADING TRAJECTORIES?

      //animate the first trajectory
      moveit_msgs::RobotTrajectory rt_msg = static_cast<const moveit_msgs::RobotTrajectory&>(*(planning_results[0]));

      //get the start point
      moveit_warehouse::MotionPlanRequestWithMetadata planning_query;
      pss.getPlanningQuery(planning_query, *scene, first_query);
      moveit_msgs::MotionPlanRequest mpr = static_cast<const moveit_msgs::MotionPlanRequest&>(*planning_query);

      //publish
      display_trajectory.trajectory_start = mpr.start_state;
      display_trajectory.trajectory.push_back(rt_msg);
      display_publisher.publish(display_trajectory);
      sleep(5.0);
    }

    //std::vector<std::string> files = boost::program_options::collect_unrecognized(po.options, boost::program_options::include_positional);
  }
  catch(mongo_ros::DbConnectException &ex)
  {
    ROS_ERROR_STREAM("Unable to connect to warehouse. If you just created the database, it could take a while for initial setup. Please try to run the benchmark again."
        << std::endl << ex.what());
  }

  ROS_INFO("Successfully performed trajectory playback");
  ros::shutdown();
  return 0;
}
<|endoftext|>


<commit_before>/* Copyright (c) 2008-2017 the MRtrix3 contributors.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, you can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * MRtrix 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.
 *
 * For more details, see http://www.mrtrix.org/.
 */

#include "gui/mrview/mode/lightbox.h"

namespace MR
{
  namespace GUI
  {
    namespace MRView
    {
      namespace Mode
      {

        bool LightBox::show_grid_lines(true);
        bool LightBox::show_volumes(false);
        size_t LightBox::n_rows(3);
        size_t LightBox::n_cols(5);
        size_t LightBox::volume_increment(1);
        float LightBox::slice_focus_increment(1.f);
        float LightBox::slice_focus_inc_adjust_rate(0.2f);
        std::string LightBox::prev_image_name;
        ssize_t LightBox::current_slice_index((LightBox::n_rows*LightBox::n_cols) / 2);

        LightBox::LightBox () :
          layout_is_dirty(true),
          slices_proj_focusdelta(n_rows*n_cols, proj_focusdelta(projection, 0.f))
        {
          Image* img = image();

          if(!img || prev_image_name != img->header().name())
            image_changed_event();
          else {
            set_volume_increment(volume_increment);
            set_slice_increment(slice_focus_increment);
          }
        }

        void LightBox::set_rows(size_t rows)
        {
          n_rows = rows;
          layout_is_dirty = true;
          updateGL();
        }

        void LightBox::set_cols(size_t cols)
        {
          n_cols = cols;
          layout_is_dirty = true;
          updateGL();
        }

        void LightBox::set_volume_increment(size_t vol_inc)
        {
          volume_increment = vol_inc;
          update_volume_indices();
          updateGL();
        }

        void LightBox::set_slice_increment(float inc)
        {
          slice_focus_increment = inc;
          update_slices_focusdelta();
          updateGL();
        }

        void LightBox::set_show_grid(bool show_grid)
        {
          show_grid_lines = show_grid;
          updateGL();
        }

        void LightBox::set_show_volumes(bool show_vol)
        {
          show_volumes = show_vol;
          if (show_vol) {
            update_volume_indices();
          }
          updateGL();
        }

        inline bool LightBox::render_volumes()
        {
          return show_volumes && image () && image()->image.ndim() == 4;
        }

        inline void LightBox::update_layout()
        {
          // Can't use vector resize() because Projection needs to be assignable
          slices_proj_focusdelta = vector<proj_focusdelta>(
              n_cols * n_rows,
              proj_focusdelta(projection, 0.f));

          update_volume_indices();

          ssize_t slice_idx = std::min<ssize_t>(current_slice_index, (n_rows * n_cols) - 1);

          set_current_slice_index(slice_idx);
          update_slices_focusdelta();

          frame_VB.clear();
          frame_VAO.clear();
        }

        void LightBox::set_current_slice_index(ssize_t slice_index)
        {
          int prev_index = current_slice_index;
          current_slice_index = slice_index;

          if (!render_volumes() && prev_index != (int)current_slice_index) {
            const Projection& slice_proj = slices_proj_focusdelta[current_slice_index].first;
            float focus_delta = slices_proj_focusdelta[current_slice_index].second;

            const Eigen::Vector3f slice_focus = move_in_out_displacement(focus_delta, slice_proj);
            set_focus(focus() + slice_focus);
            update_slices_focusdelta();
          } else if (volume_indices[slice_index] == -1)
              current_slice_index = prev_index;
        }

        void LightBox::update_slices_focusdelta()
        {
          const int current_slice_index_int = current_slice_index;
          for(int i = 0, N = slices_proj_focusdelta.size(); i < N; ++i) {
            slices_proj_focusdelta[i].second =
              slice_focus_increment * (i - current_slice_index_int);
          }
        }

        void LightBox::update_volume_indices()
        {
          bool is_4d = image () && image()->image.ndim() == 4;
          volume_indices.resize (n_rows * n_cols, 0);

          if (!is_4d)
            return;

          int n_vols = image()->image.size(3);
          int current_vol = image()->image.index(3);

          int initial_vol = current_vol + (int)volume_increment *- (int)current_slice_index;
          if (initial_vol < 0)
            current_vol = volume_increment * current_slice_index;

          for(int i = 0, N = volume_indices.size(); i < N; ++i) {
            int vol_index = current_vol + (int)volume_increment * (i - (int)current_slice_index);
            vol_index = vol_index < 0 || vol_index >= n_vols ? -1 : vol_index;
            volume_indices[i] = vol_index;
          }

          for (ssize_t i = current_slice_index; i >= 0; --i) {
            current_slice_index = i;
            if (volume_indices[i] >= 0)
              break;
          }
        }

        void LightBox::draw_plane_primitive (int axis, Displayable::Shader& shader_program, Projection& with_projection)
        {
          ASSERT_GL_MRVIEW_CONTEXT_IS_CURRENT;
          if (visible)
            image()->render3D (shader_program, with_projection, with_projection.depth_of (focus()));
          render_tools (with_projection, false, axis, slice (axis));
          ASSERT_GL_MRVIEW_CONTEXT_IS_CURRENT;
        }

        void LightBox::paint(Projection&)
        {
          ASSERT_GL_MRVIEW_CONTEXT_IS_CURRENT;
          // Setup OpenGL environment:
          gl::Disable (gl::BLEND);
          gl::Disable (gl::DEPTH_TEST);
          gl::DepthMask (gl::FALSE_);
          gl::ColorMask (gl::TRUE_, gl::TRUE_, gl::TRUE_, gl::TRUE_);

          GLint x = projection.x_position(), y = projection.y_position();
          GLint w = projection.width(), h = projection.height();
          GLfloat dw = w / (float)n_cols, dh = h / (float)n_rows;

          const Eigen::Vector3f orig_focus = window().focus();

          if (layout_is_dirty) {
            update_layout();
            layout_is_dirty = false;
          }

          bool rend_vols = render_volumes();

          ssize_t slice_idx = 0;
          for(size_t row = 0; row < n_rows; ++row) {
            for(size_t col = 0; col < n_cols; ++col, ++slice_idx) {
              Projection& slice_proj = slices_proj_focusdelta[slice_idx].first;

              bool render_plane = true;

              // Place the first slice in the top-left corner
              slice_proj.set_viewport(window(), x + dw * col, y + h - (dh * (row+1)), dw, dh);

              // We need to setup the modelview/proj matrices before we set the new focus
              // because move_in_out_displacement is reliant on MVP
              setup_projection (plane(), slice_proj);

              if (rend_vols) {
                if (volume_indices[slice_idx] != -1)
                  image()->image.index(3) = volume_indices[slice_idx];
                else
                  render_plane = false;
              }

              else {
                float focus_delta = slices_proj_focusdelta[slice_idx].second;
                Eigen::Vector3f slice_focus = move_in_out_displacement(focus_delta, slice_proj);
                set_focus(orig_focus + slice_focus);
              }

              if (render_plane)
                draw_plane_primitive(plane(), slice_shader, slice_proj);

              if(slice_idx == current_slice_index) {
                // Drawing plane may alter the depth test state
                // so need to ensure that crosshairs/labels will be visible
                gl::Disable (gl::DEPTH_TEST);
                draw_crosshairs(slice_proj);
                draw_orientation_labels(slice_proj);
              }
            }
          }

          // Restore view state
          if(rend_vols && volume_indices[current_slice_index] >= 0)
            image()->image.index(3) = volume_indices[current_slice_index];
          set_focus(orig_focus);
          projection.set_viewport(window(), x, y, w, h);

          // Users may want to screen capture without grid lines
          if(show_grid_lines) {
            gl::Disable(gl::DEPTH_TEST);
            draw_grid();
          }
          ASSERT_GL_MRVIEW_CONTEXT_IS_CURRENT;
        }

        void LightBox::draw_grid()
        {
          ASSERT_GL_MRVIEW_CONTEXT_IS_CURRENT;
          if(n_cols < 1 && n_rows < 1)
            return;

          size_t num_points = ((n_rows - 1) + (n_cols - 1)) * 4;

          GL::mat4 MV = GL::identity();
          GL::mat4 P = GL::ortho (0, width(), 0, height(), -1.0, 1.0);
          projection.set (MV, P);

          if (!frame_VB || !frame_VAO) {
            frame_VB.gen();
            frame_VAO.gen();

            frame_VB.bind (gl::ARRAY_BUFFER);
            frame_VAO.bind();

            gl::EnableVertexAttribArray (0);
            gl::VertexAttribPointer (0, 2, gl::FLOAT, gl::FALSE_, 0, (void*)0);

            GLfloat data[num_points];

            // Grid line stride
            float x_inc = 2.f / n_cols;
            float y_inc = 2.f / n_rows;

            size_t pt_idx = 0;
            // Row grid lines
            for(size_t row = 1; row < n_rows; ++row, pt_idx += 4) {
              float y_pos = (y_inc * row) - 1.f;
              data[pt_idx] = -1.f;
              data[pt_idx+1] = y_pos;
              data[pt_idx+2] = 1.f;
              data[pt_idx+3] = y_pos;
            }

            // Column grid lines
            for(size_t col = 1; col < n_cols; ++col, pt_idx += 4) {
              float x_pos = (x_inc * col) - 1.f;
              data[pt_idx] = x_pos;
              data[pt_idx+1] = -1.f;
              data[pt_idx+2] = x_pos;
              data[pt_idx+3] = 1.f;
            }

            gl::BufferData (gl::ARRAY_BUFFER, sizeof(data), data, gl::STATIC_DRAW);
          }
          else
            frame_VAO.bind();

          if (!frame_program) {
            GL::Shader::Vertex vertex_shader (
                "layout(location=0) in vec2 pos;\n"
                "void main () {\n"
                "  gl_Position = vec4 (pos, 0.0, 1.0);\n"
                "}\n");
            GL::Shader::Fragment fragment_shader (
                "out vec3 color;\n"
                "void main () {\n"
                "  color = vec3 (0.1);\n"
                "}\n");
            frame_program.attach (vertex_shader);
            frame_program.attach (fragment_shader);
            frame_program.link();
          }

          frame_program.start();
          gl::DrawArrays (gl::LINES, 0, num_points / 2);
          frame_program.stop();
          ASSERT_GL_MRVIEW_CONTEXT_IS_CURRENT;
        }

        void LightBox::mouse_press_event()
        {
          GLint x = projection.x_position(), y = projection.y_position();
          GLint w = projection.width(), h = projection.height();
          GLint dw = w / n_cols, dh = h / n_rows;

          const auto& mouse_pos = window().mouse_position();

          size_t col = (mouse_pos.x() - x) / dw;
          size_t row = n_rows - (mouse_pos.y() - y) / dh - 1;

          if(col < n_cols && row < n_rows) {
            set_current_slice_index(slice_index(row, col));
          }
        }

        // Called when we get a mouse move event
        void LightBox::set_focus_event()
        {
          Base::set_focus_event();
          mouse_press_event();
        }

        void LightBox::image_changed_event()
        {
          Base::image_changed_event();

          update_volume_indices();

          if(image()) {
            const auto& header = image()->header();
            if (prev_image_name.empty()) {
              float slice_inc = std::pow (header.spacing(0)*header.spacing(1)*header.spacing(2), 1.f/3.f);
              slice_focus_inc_adjust_rate = slice_inc / 5.f;

              set_slice_increment(slice_inc);
              emit slice_increment_reset();
            }

            prev_image_name = image()->header().name();
          }
          else
            prev_image_name.clear();
        }

      }
    }
  }
}
<commit_msg>mrview: lightbox: Correctly update current slice focus<commit_after>/* Copyright (c) 2008-2017 the MRtrix3 contributors.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, you can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * MRtrix 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.
 *
 * For more details, see http://www.mrtrix.org/.
 */

#include "gui/mrview/mode/lightbox.h"

namespace MR
{
  namespace GUI
  {
    namespace MRView
    {
      namespace Mode
      {

        bool LightBox::show_grid_lines(true);
        bool LightBox::show_volumes(false);
        size_t LightBox::n_rows(3);
        size_t LightBox::n_cols(5);
        size_t LightBox::volume_increment(1);
        float LightBox::slice_focus_increment(1.f);
        float LightBox::slice_focus_inc_adjust_rate(0.2f);
        std::string LightBox::prev_image_name;
        ssize_t LightBox::current_slice_index((LightBox::n_rows*LightBox::n_cols) / 2);

        LightBox::LightBox () :
          layout_is_dirty(true),
          slices_proj_focusdelta(n_rows*n_cols, proj_focusdelta(projection, 0.f))
        {
          Image* img = image();

          if(!img || prev_image_name != img->header().name())
            image_changed_event();
          else {
            set_volume_increment(volume_increment);
            set_slice_increment(slice_focus_increment);
          }
        }

        void LightBox::set_rows(size_t rows)
        {
          n_rows = rows;
          layout_is_dirty = true;
          updateGL();
        }

        void LightBox::set_cols(size_t cols)
        {
          n_cols = cols;
          layout_is_dirty = true;
          updateGL();
        }

        void LightBox::set_volume_increment(size_t vol_inc)
        {
          volume_increment = vol_inc;
          update_volume_indices();
          updateGL();
        }

        void LightBox::set_slice_increment(float inc)
        {
          slice_focus_increment = inc;
          update_slices_focusdelta();
          updateGL();
        }

        void LightBox::set_show_grid(bool show_grid)
        {
          show_grid_lines = show_grid;
          updateGL();
        }

        void LightBox::set_show_volumes(bool show_vol)
        {
          show_volumes = show_vol;
          if (show_vol)
            update_volume_indices();
          else {
            // Force focus update
            ssize_t prev_index = current_slice_index;
            current_slice_index = -1;
            set_current_slice_index(prev_index);
          }
          updateGL();
        }

        inline bool LightBox::render_volumes()
        {
          return show_volumes && image () && image()->image.ndim() == 4;
        }

        inline void LightBox::update_layout()
        {
          // Can't use vector resize() because Projection needs to be assignable
          slices_proj_focusdelta = vector<proj_focusdelta>(
              n_cols * n_rows,
              proj_focusdelta(projection, 0.f));

          update_volume_indices();

          ssize_t slice_idx = std::min<ssize_t>(current_slice_index, (n_rows * n_cols) - 1);

          set_current_slice_index(slice_idx);
          update_slices_focusdelta();

          frame_VB.clear();
          frame_VAO.clear();
        }

        void LightBox::set_current_slice_index(ssize_t slice_index)
        {
          int prev_index = current_slice_index;
          current_slice_index = slice_index;

          if (!render_volumes() && prev_index != (int)current_slice_index) {
            const Projection& slice_proj = slices_proj_focusdelta[current_slice_index].first;
            float focus_delta = slices_proj_focusdelta[current_slice_index].second;

            const Eigen::Vector3f slice_focus = move_in_out_displacement(focus_delta, slice_proj);
            set_focus(focus() + slice_focus);
            update_slices_focusdelta();
          } else if (volume_indices[slice_index] == -1)
              current_slice_index = prev_index;
        }

        void LightBox::update_slices_focusdelta()
        {
          const int current_slice_index_int = current_slice_index;
          for(int i = 0, N = slices_proj_focusdelta.size(); i < N; ++i) {
            slices_proj_focusdelta[i].second =
              slice_focus_increment * (i - current_slice_index_int);
          }
        }

        void LightBox::update_volume_indices()
        {
          bool is_4d = image () && image()->image.ndim() == 4;
          volume_indices.resize (n_rows * n_cols, 0);

          if (!is_4d)
            return;

          int n_vols = image()->image.size(3);
          int current_vol = image()->image.index(3);

          int initial_vol = current_vol + (int)volume_increment *- (int)current_slice_index;
          if (initial_vol < 0)
            current_vol = volume_increment * current_slice_index;

          for(int i = 0, N = volume_indices.size(); i < N; ++i) {
            int vol_index = current_vol + (int)volume_increment * (i - (int)current_slice_index);
            vol_index = vol_index < 0 || vol_index >= n_vols ? -1 : vol_index;
            volume_indices[i] = vol_index;
          }

          for (ssize_t i = current_slice_index; i >= 0; --i) {
            current_slice_index = i;
            if (volume_indices[i] >= 0)
              break;
          }
        }

        void LightBox::draw_plane_primitive (int axis, Displayable::Shader& shader_program, Projection& with_projection)
        {
          ASSERT_GL_MRVIEW_CONTEXT_IS_CURRENT;
          if (visible)
            image()->render3D (shader_program, with_projection, with_projection.depth_of (focus()));
          render_tools (with_projection, false, axis, slice (axis));
          ASSERT_GL_MRVIEW_CONTEXT_IS_CURRENT;
        }

        void LightBox::paint(Projection&)
        {
          ASSERT_GL_MRVIEW_CONTEXT_IS_CURRENT;
          // Setup OpenGL environment:
          gl::Disable (gl::BLEND);
          gl::Disable (gl::DEPTH_TEST);
          gl::DepthMask (gl::FALSE_);
          gl::ColorMask (gl::TRUE_, gl::TRUE_, gl::TRUE_, gl::TRUE_);

          GLint x = projection.x_position(), y = projection.y_position();
          GLint w = projection.width(), h = projection.height();
          GLfloat dw = w / (float)n_cols, dh = h / (float)n_rows;

          const Eigen::Vector3f orig_focus = window().focus();

          if (layout_is_dirty) {
            update_layout();
            layout_is_dirty = false;
          }

          bool rend_vols = render_volumes();

          ssize_t slice_idx = 0;
          for(size_t row = 0; row < n_rows; ++row) {
            for(size_t col = 0; col < n_cols; ++col, ++slice_idx) {
              Projection& slice_proj = slices_proj_focusdelta[slice_idx].first;

              bool render_plane = true;

              // Place the first slice in the top-left corner
              slice_proj.set_viewport(window(), x + dw * col, y + h - (dh * (row+1)), dw, dh);

              // We need to setup the modelview/proj matrices before we set the new focus
              // because move_in_out_displacement is reliant on MVP
              setup_projection (plane(), slice_proj);

              if (rend_vols) {
                if (volume_indices[slice_idx] != -1)
                  image()->image.index(3) = volume_indices[slice_idx];
                else
                  render_plane = false;
              }

              else {
                float focus_delta = slices_proj_focusdelta[slice_idx].second;
                Eigen::Vector3f slice_focus = move_in_out_displacement(focus_delta, slice_proj);
                set_focus(orig_focus + slice_focus);
              }

              if (render_plane)
                draw_plane_primitive(plane(), slice_shader, slice_proj);

              if(slice_idx == current_slice_index) {
                // Drawing plane may alter the depth test state
                // so need to ensure that crosshairs/labels will be visible
                gl::Disable (gl::DEPTH_TEST);
                draw_crosshairs(slice_proj);
                draw_orientation_labels(slice_proj);
              }
            }
          }

          // Restore view state
          if(rend_vols && volume_indices[current_slice_index] >= 0)
            image()->image.index(3) = volume_indices[current_slice_index];
          set_focus(orig_focus);
          projection.set_viewport(window(), x, y, w, h);

          // Users may want to screen capture without grid lines
          if(show_grid_lines) {
            gl::Disable(gl::DEPTH_TEST);
            draw_grid();
          }
          ASSERT_GL_MRVIEW_CONTEXT_IS_CURRENT;
        }

        void LightBox::draw_grid()
        {
          ASSERT_GL_MRVIEW_CONTEXT_IS_CURRENT;
          if(n_cols < 1 && n_rows < 1)
            return;

          size_t num_points = ((n_rows - 1) + (n_cols - 1)) * 4;

          GL::mat4 MV = GL::identity();
          GL::mat4 P = GL::ortho (0, width(), 0, height(), -1.0, 1.0);
          projection.set (MV, P);

          if (!frame_VB || !frame_VAO) {
            frame_VB.gen();
            frame_VAO.gen();

            frame_VB.bind (gl::ARRAY_BUFFER);
            frame_VAO.bind();

            gl::EnableVertexAttribArray (0);
            gl::VertexAttribPointer (0, 2, gl::FLOAT, gl::FALSE_, 0, (void*)0);

            GLfloat data[num_points];

            // Grid line stride
            float x_inc = 2.f / n_cols;
            float y_inc = 2.f / n_rows;

            size_t pt_idx = 0;
            // Row grid lines
            for(size_t row = 1; row < n_rows; ++row, pt_idx += 4) {
              float y_pos = (y_inc * row) - 1.f;
              data[pt_idx] = -1.f;
              data[pt_idx+1] = y_pos;
              data[pt_idx+2] = 1.f;
              data[pt_idx+3] = y_pos;
            }

            // Column grid lines
            for(size_t col = 1; col < n_cols; ++col, pt_idx += 4) {
              float x_pos = (x_inc * col) - 1.f;
              data[pt_idx] = x_pos;
              data[pt_idx+1] = -1.f;
              data[pt_idx+2] = x_pos;
              data[pt_idx+3] = 1.f;
            }

            gl::BufferData (gl::ARRAY_BUFFER, sizeof(data), data, gl::STATIC_DRAW);
          }
          else
            frame_VAO.bind();

          if (!frame_program) {
            GL::Shader::Vertex vertex_shader (
                "layout(location=0) in vec2 pos;\n"
                "void main () {\n"
                "  gl_Position = vec4 (pos, 0.0, 1.0);\n"
                "}\n");
            GL::Shader::Fragment fragment_shader (
                "out vec3 color;\n"
                "void main () {\n"
                "  color = vec3 (0.1);\n"
                "}\n");
            frame_program.attach (vertex_shader);
            frame_program.attach (fragment_shader);
            frame_program.link();
          }

          frame_program.start();
          gl::DrawArrays (gl::LINES, 0, num_points / 2);
          frame_program.stop();
          ASSERT_GL_MRVIEW_CONTEXT_IS_CURRENT;
        }

        void LightBox::mouse_press_event()
        {
          GLint x = projection.x_position(), y = projection.y_position();
          GLint w = projection.width(), h = projection.height();
          GLint dw = w / n_cols, dh = h / n_rows;

          const auto& mouse_pos = window().mouse_position();

          size_t col = (mouse_pos.x() - x) / dw;
          size_t row = n_rows - (mouse_pos.y() - y) / dh - 1;

          if(col < n_cols && row < n_rows) {
            set_current_slice_index(slice_index(row, col));
          }
        }

        // Called when we get a mouse move event
        void LightBox::set_focus_event()
        {
          Base::set_focus_event();
          mouse_press_event();
        }

        void LightBox::image_changed_event()
        {
          Base::image_changed_event();

          update_volume_indices();

          if(image()) {
            const auto& header = image()->header();
            if (prev_image_name.empty()) {
              float slice_inc = std::pow (header.spacing(0)*header.spacing(1)*header.spacing(2), 1.f/3.f);
              slice_focus_inc_adjust_rate = slice_inc / 5.f;

              set_slice_increment(slice_inc);
              emit slice_increment_reset();
            }

            prev_image_name = image()->header().name();
          }
          else
            prev_image_name.clear();
        }

      }
    }
  }
}
<|endoftext|>


<commit_before>#include "OutputVars.h"
#include "UnitConst.h" //For unit conversion factors
#include "System.h"
#include "MoveSettings.h"
#include "MoleculeLookup.h"

#if ENSEMBLE == GEMC
#include "MoveConst.h" //For box constants, if we're calculating Hv
#endif

OutputVars::OutputVars(System & sys, StaticVals const& statV) :
  calc(sys.calcEnergy) { InitRef(sys, statV); }

void OutputVars::InitRef(System & sys, StaticVals const& statV)
{
  T_in_K = statV.forcefield.T_in_K;
  volumeRef = sys.boxDimRef.volume;
  axisRef = &sys.boxDimRef.axis;
  volInvRef = sys.boxDimRef.volInv;
  energyTotRef = & sys.potential.totalEnergy;
  virialTotRef = & sys.potential.totalVirial;
  energyRef = sys.potential.boxEnergy;
  virialRef = sys.potential.boxVirial; //
  kindsRef = statV.mol.kinds;
  molLookupRef = & sys.molLookupRef;
  moveSetRef = & sys.moveSettings;
  movePercRef = statV.movePerc;
  pCalcFreq = statV.simEventFreq.pCalcFreq;
  pressureCalc = statV.simEventFreq.pressureCalc;

  virial = new Virial[BOXES_WITH_U_NB];
}

uint OutputVars::GetTries(uint sub)
{
  return (sub < mv::SCALEABLE ?
          moveSetRef->tries[sub] + moveSetRef->tempTries[sub] :
          moveSetRef->tries[sub]);
}

uint OutputVars::GetAccepted(uint sub)
{
  return (sub < mv::SCALEABLE ?
          moveSetRef->accepted[sub] + moveSetRef->tempAccepted[sub] :
          moveSetRef->accepted[sub]);
}

double OutputVars::GetScale(uint sub)
{
  return moveSetRef->scale[sub];
}

double OutputVars::GetAcceptPercent(uint sub)
{
  if(GetTries(sub)==0)
    return 0.0;
  return (double)(GetAccepted(sub))/(double)(GetTries(sub))*100.0;
}

void OutputVars::Init(pdb_setup::Atoms const& atoms)
{
  //Init vals.
  numKinds = molLookupRef->GetNumKind();
  resKindNames = atoms.resKindNames;

  //Allocate arrays,
  uint kTot = BOX_TOTAL * numKinds;
  numByBox = new uint [BOX_TOTAL];
  numByKindBox = new uint [kTot];
  densityByKindBox = new double [kTot];
  if (numKinds > 1)
    molFractionByKindBox = new double [kTot];
}

OutputVars::~OutputVars(void)
{
  if ( numByBox != NULL )
    delete[] numByBox;
  if ( numByKindBox != NULL )
    delete[] numByKindBox;
  if ( numKinds > 1 && molFractionByKindBox != NULL )
    delete[] molFractionByKindBox;
  if ( densityByKindBox != NULL )
    delete[] densityByKindBox;
}

void OutputVars::CalcAndConvert(ulong step)
{
  double rawPressure[BOXES_WITH_U_NB];

#if ENSEMBLE == GEMC
  //Which box is the liquid in gibbs ensemble
  uint liqBox = mv::BOX0, vapBox = mv::BOX1;
#endif

  molLookupRef->TotalAndDensity(numByBox,  numByKindBox, molFractionByKindBox,
                                densityByKindBox, volInvRef);

#if ENSEMBLE == GEMC
  //Determine which box is liquid for purposes of heat of vap.
  if (densityByKindBox[numKinds] > densityByKindBox[0])
  {
    vapBox = mv::BOX0;
    liqBox = mv::BOX1;
  }
#endif

  for (uint b = 0; b < BOXES_WITH_U_NB; b++)
  {
    //Account for dimensionality of virial (raw "virial" is actually a
    //multiple of the true virial, based on the dimensions stress is exerted
    //in)

    if (((step + 1) % pCalcFreq == 0) && pressureCalc)
    {
      virialRef[b] = calc.ForceCalc(b);
      *virialTotRef += virialRef[b];
      //calculate surface tension in mN/M
      surfaceTens[b] = (virialRef[b].totalTens[2][2] - 0.5 *
			(virialRef[b].totalTens[0][0] +
			 virialRef[b].totalTens[1][1]));
      surfaceTens[b] *= unit::K_TO_MN_PER_M /
	(2.0 * axisRef->Get(b).x * axisRef->Get(b).y);

      //save the pressure tensor for print
      for (int i = 0; i < 3; i++)
      {
	 for (int j = 0; j < 3; j++)
	 {
	    //convert K to bar
	    pressureTens[b][i][j] = virialRef[b].totalTens[i][j] *
	      unit::K_MOLECULE_PER_A3_TO_BAR / volumeRef[b];
	 }
      }
    }

    virial[b] = virialRef[b];
    virial[b] /= unit::DIMENSIONALITY;
    virial[b] /= volumeRef[b];
    virial[b].Total();

    rawPressure[b] = 0.0;
    densityTot[b] = 0.0;
    for (uint k = 0; k < numKinds; k++)
    {
      double * density = &densityByKindBox[k+numKinds*b];

      // Instead of converting to mass first
      // (an alternate route to calculate the ideal gas pressure)
      // the form of the Boltzmann constant that kcal/mol/K is used
      // such that a single conversion factor can be applied to both
      // the ideal and virial components of the pressure.
      rawPressure[b] += *density;
    }
    // Finish ideal component
    rawPressure[b] *= T_in_K;
    // Add the virial component
    rawPressure[b] += virial[b].total;

    // Convert to desired units
    // ( starting: K * molecule / Angstrom^3 )
    pressure[b] = rawPressure[b];
    pressure[b] *= unit::K_MOLECULE_PER_A3_TO_BAR;
  }
  for (uint b = 0; b < BOX_TOTAL; b++)
  {
    densityTot[b] = 0.0;
    for (uint k = 0; k < numKinds; k++)
    {
      double * density = &densityByKindBox[k+numKinds*b];

      // Convert density to g/ml (which is equivalent to g/cm3)
      // To get kg/m3, multiply output densities by 1000.
      *density *= unit::MOLECULES_PER_A3_TO_MOL_PER_CM3 *
                  kindsRef[k].molMass;
      densityTot[b] += densityByKindBox[k+numKinds*b];
    }
    densityTot[b] *= 1000;
  }
#if ENSEMBLE == GEMC
  // delta Hv = (Uv-Ul) + P(Vv-Vl)
  heatOfVap = energyRef[vapBox].total/numByBox[vapBox] -
              energyRef[liqBox].total/numByBox[liqBox] +
              rawPressure[vapBox]*(volumeRef[vapBox]/numByBox[vapBox] -
                                   volumeRef[liqBox]/numByBox[liqBox]);
  heatOfVap *= unit::K_TO_KJ_PER_MOL;
#endif

}
<commit_msg>calc pressure at step 0<commit_after>#include "OutputVars.h"
#include "UnitConst.h" //For unit conversion factors
#include "System.h"
#include "MoveSettings.h"
#include "MoleculeLookup.h"

#if ENSEMBLE == GEMC
#include "MoveConst.h" //For box constants, if we're calculating Hv
#endif

OutputVars::OutputVars(System & sys, StaticVals const& statV) :
  calc(sys.calcEnergy) { InitRef(sys, statV); }

void OutputVars::InitRef(System & sys, StaticVals const& statV)
{
  T_in_K = statV.forcefield.T_in_K;
  volumeRef = sys.boxDimRef.volume;
  axisRef = &sys.boxDimRef.axis;
  volInvRef = sys.boxDimRef.volInv;
  energyTotRef = & sys.potential.totalEnergy;
  virialTotRef = & sys.potential.totalVirial;
  energyRef = sys.potential.boxEnergy;
  virialRef = sys.potential.boxVirial; //
  kindsRef = statV.mol.kinds;
  molLookupRef = & sys.molLookupRef;
  moveSetRef = & sys.moveSettings;
  movePercRef = statV.movePerc;
  pCalcFreq = statV.simEventFreq.pCalcFreq;
  pressureCalc = statV.simEventFreq.pressureCalc;

  virial = new Virial[BOXES_WITH_U_NB];
}

uint OutputVars::GetTries(uint sub)
{
  return (sub < mv::SCALEABLE ?
          moveSetRef->tries[sub] + moveSetRef->tempTries[sub] :
          moveSetRef->tries[sub]);
}

uint OutputVars::GetAccepted(uint sub)
{
  return (sub < mv::SCALEABLE ?
          moveSetRef->accepted[sub] + moveSetRef->tempAccepted[sub] :
          moveSetRef->accepted[sub]);
}

double OutputVars::GetScale(uint sub)
{
  return moveSetRef->scale[sub];
}

double OutputVars::GetAcceptPercent(uint sub)
{
  if(GetTries(sub)==0)
    return 0.0;
  return (double)(GetAccepted(sub))/(double)(GetTries(sub))*100.0;
}

void OutputVars::Init(pdb_setup::Atoms const& atoms)
{
  //Init vals.
  numKinds = molLookupRef->GetNumKind();
  resKindNames = atoms.resKindNames;

  //Allocate arrays,
  uint kTot = BOX_TOTAL * numKinds;
  numByBox = new uint [BOX_TOTAL];
  numByKindBox = new uint [kTot];
  densityByKindBox = new double [kTot];
  if (numKinds > 1)
    molFractionByKindBox = new double [kTot];
}

OutputVars::~OutputVars(void)
{
  if ( numByBox != NULL )
    delete[] numByBox;
  if ( numByKindBox != NULL )
    delete[] numByKindBox;
  if ( numKinds > 1 && molFractionByKindBox != NULL )
    delete[] molFractionByKindBox;
  if ( densityByKindBox != NULL )
    delete[] densityByKindBox;
}

void OutputVars::CalcAndConvert(ulong step)
{
  double rawPressure[BOXES_WITH_U_NB];

#if ENSEMBLE == GEMC
  //Which box is the liquid in gibbs ensemble
  uint liqBox = mv::BOX0, vapBox = mv::BOX1;
#endif

  molLookupRef->TotalAndDensity(numByBox,  numByKindBox, molFractionByKindBox,
                                densityByKindBox, volInvRef);

#if ENSEMBLE == GEMC
  //Determine which box is liquid for purposes of heat of vap.
  if (densityByKindBox[numKinds] > densityByKindBox[0])
  {
    vapBox = mv::BOX0;
    liqBox = mv::BOX1;
  }
#endif

  for (uint b = 0; b < BOXES_WITH_U_NB; b++)
  {
    //Account for dimensionality of virial (raw "virial" is actually a
    //multiple of the true virial, based on the dimensions stress is exerted
    //in)

    if (((step + 1) % pCalcFreq == 0) && pressureCalc)
    {
      virialRef[b] = calc.ForceCalc(b);
      *virialTotRef += virialRef[b];
    }

    //calculate surface tension in mN/M
    surfaceTens[b] = (virialRef[b].totalTens[2][2] - 0.5 *
		      (virialRef[b].totalTens[0][0] +
		       virialRef[b].totalTens[1][1]));
    surfaceTens[b] *= unit::K_TO_MN_PER_M /
      (2.0 * axisRef->Get(b).x * axisRef->Get(b).y);

    //save the pressure tensor for print
    for (int i = 0; i < 3; i++)
    {
       for (int j = 0; j < 3; j++)
       {
	  //convert K to bar
	  pressureTens[b][i][j] = virialRef[b].totalTens[i][j] *
	    unit::K_MOLECULE_PER_A3_TO_BAR / volumeRef[b];
       }
    }

    virial[b] = virialRef[b];
    virial[b] /= unit::DIMENSIONALITY;
    virial[b] /= volumeRef[b];
    virial[b].Total();

    rawPressure[b] = 0.0;
    densityTot[b] = 0.0;
    for (uint k = 0; k < numKinds; k++)
    {
      double * density = &densityByKindBox[k+numKinds*b];

      // Instead of converting to mass first
      // (an alternate route to calculate the ideal gas pressure)
      // the form of the Boltzmann constant that kcal/mol/K is used
      // such that a single conversion factor can be applied to both
      // the ideal and virial components of the pressure.
      rawPressure[b] += *density;
    }
    // Finish ideal component
    rawPressure[b] *= T_in_K;
    // Add the virial component
    rawPressure[b] += virial[b].total;

    // Convert to desired units
    // ( starting: K * molecule / Angstrom^3 )
    pressure[b] = rawPressure[b];
    pressure[b] *= unit::K_MOLECULE_PER_A3_TO_BAR;
  }
  for (uint b = 0; b < BOX_TOTAL; b++)
  {
    densityTot[b] = 0.0;
    for (uint k = 0; k < numKinds; k++)
    {
      double * density = &densityByKindBox[k+numKinds*b];

      // Convert density to g/ml (which is equivalent to g/cm3)
      // To get kg/m3, multiply output densities by 1000.
      *density *= unit::MOLECULES_PER_A3_TO_MOL_PER_CM3 *
                  kindsRef[k].molMass;
      densityTot[b] += densityByKindBox[k+numKinds*b];
    }
    densityTot[b] *= 1000;
  }
#if ENSEMBLE == GEMC
  // delta Hv = (Uv-Ul) + P(Vv-Vl)
  heatOfVap = energyRef[vapBox].total/numByBox[vapBox] -
              energyRef[liqBox].total/numByBox[liqBox] +
              rawPressure[vapBox]*(volumeRef[vapBox]/numByBox[vapBox] -
                                   volumeRef[liqBox]/numByBox[liqBox]);
  heatOfVap *= unit::K_TO_KJ_PER_MOL;
#endif

}
<|endoftext|>


<commit_before>#include "cmm_socket.private.h"
#include "csocket.h"
#include "debug.h"
#include "timeops.h"
#include "cmm_socket_control.h"
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include "csocket_sender.h"
#include "csocket_receiver.h"
#include "csocket_mapping.h"
#include <functional>
using std::max;

CSocketPtr
CSocket::create(boost::weak_ptr<CMMSocketImpl> sk_,
                struct net_interface local_iface_,
                struct net_interface remote_iface_,
                int accepted_sock)
{
    CSocketPtr new_csock(new CSocket(sk_, local_iface_,
                                     remote_iface_, accepted_sock));
    new_csock->self_ptr = new_csock;
    return new_csock;
}

CSocket::CSocket(boost::weak_ptr<CMMSocketImpl> sk_,
                 struct net_interface local_iface_,
                 struct net_interface remote_iface_,
                 int accepted_sock)
    : sk(sk_),
      local_iface(local_iface_), remote_iface(remote_iface_),
      stats(local_iface, remote_iface),
      csock_sendr(NULL), csock_recvr(NULL), irob_indexes(local_iface_.labels)
{
    assert(sk);
    if (accepted_sock == -1) {
        osfd = socket(sk->sock_family, sk->sock_type, sk->sock_protocol);
        if (osfd < 0) {
            /* out of file descriptors or memory at this point */
            throw std::runtime_error("Out of FDs or memory!");
        }

        sk->set_all_sockopts(osfd);
    } else {
        osfd = accepted_sock;
    }

    int on = 1;
    int rc;
    /* Make sure that this socket is TCP_NODELAY for good performance */
    struct protoent *pe = getprotobyname("TCP");
    if (pe) {
	rc = setsockopt (osfd, pe->p_proto, TCP_NODELAY,
			 (char *) &on, sizeof(on));
    } else {
	rc = setsockopt (osfd, 6, TCP_NODELAY,
			 (char *) &on, sizeof(on));
    }
    if (rc < 0) {
	dbgprintf("Cannot make socket TCP_NODELAY");
    }
}

CSocket::~CSocket()
{
    dbgprintf("CSocket %d is being destroyed\n", osfd);
    if (osfd > 0) {
	/* if it's a real open socket */
        assert(csock_sendr == NULL && csock_recvr == NULL);
	close(osfd);
    }
}

int
CSocket::phys_connect()
{
    struct sockaddr_in local_addr, remote_addr;

    // XXX-TODO: don't assume it's an inet socket

    local_addr.sin_family = AF_INET;
    local_addr.sin_addr = local_iface.ip_addr;
    local_addr.sin_port = 0;

    remote_addr.sin_family = AF_INET;
    remote_addr.sin_addr = remote_iface.ip_addr;
    remote_addr.sin_port = sk->remote_listener_port;

    int rc = bind(osfd, (struct sockaddr *)&local_addr,
              sizeof(local_addr));
    if (rc < 0) {
	perror("bind");
	dbgprintf("Failed to bind osfd %d to %s:%d\n",
		  osfd, inet_ntoa(local_addr.sin_addr),
		  ntohs(local_addr.sin_port));
	return rc;
    }
    dbgprintf("Successfully bound osfd %d to %s:%d\n",
	      osfd, inet_ntoa(local_addr.sin_addr),
	      ntohs(local_addr.sin_port));

    rc = connect(osfd, (struct sockaddr *)&remote_addr,
		 sizeof(remote_addr));
    if (rc < 0) {
	perror("connect");
	dbgprintf("Failed to connect osfd %d to %s:%d\n",
		  osfd, inet_ntoa(remote_addr.sin_addr),
		  ntohs(remote_addr.sin_port));
	return rc;
    }
    struct CMMSocketControlHdr hdr;
    memset(&hdr, 0, sizeof(hdr));
    hdr.type = htons(CMM_CONTROL_MSG_NEW_INTERFACE);
    hdr.send_labels = 0;
    hdr.op.new_interface.ip_addr = local_iface.ip_addr;
    hdr.op.new_interface.labels = htonl(local_iface.labels);
    hdr.op.new_interface.bandwidth = htonl(local_iface.bandwidth);
    hdr.op.new_interface.RTT = htonl(local_iface.RTT);
    rc = send(osfd, &hdr, sizeof(hdr), 0);
    if (rc != sizeof(hdr)) {
        perror("send");
        dbgprintf("Failed to send interface info\n");
        return rc;
    }

    startup_workers();
    return 0;
}

void
CSocket::startup_workers()
{
    if (!csock_sendr && !csock_recvr) {
	csock_sendr = new CSocketSender(CSocketPtr(self_ptr));
	csock_recvr = new CSocketReceiver(CSocketPtr(self_ptr));
	int rc = csock_sendr->start();
        if (rc != 0) {
            throw std::runtime_error("Failed to create csocket_sender thread!");
        }
	rc = csock_recvr->start();
        if (rc != 0) {
            throw std::runtime_error("Failed to create csocket_receiver thread!");
        }
    }
}

/* must not be holding sk->scheduling_state_lock. */
bool
CSocket::matches(u_long send_labels)
{
    return sk->csock_map->csock_matches(this, send_labels);
}

u_long
CSocket::bandwidth()
{
    u_long bw_est;
    if (stats.get_estimate(NET_STATS_BW_UP, bw_est)) {
        return bw_est;
    } else {
        return iface_bandwidth(local_iface, remote_iface);
    }
}

double CSocket::RTT()
{
    u_long latency_est;
    if (stats.get_estimate(NET_STATS_LATENCY, latency_est)) {
        return (double)(latency_est * 2);
    } else {
        return iface_RTT(local_iface, remote_iface);
    }
}

struct timespec
CSocket::retransmission_timeout()
{
    // have a fairly high floor on this so that we don't
    //  flood the socket with spurious retransmissions
    struct timespec min_rto = {30, 0};
    struct timespec default_rto = {120, 0};

    int bufsize = 0;
    socklen_t len = sizeof(bufsize);
    int rc = getsockopt(osfd, SOL_SOCKET, SO_SNDBUF, &bufsize, &len);
    if (rc < 0) {
	dbgprintf("Failed to get socket send buffer size: %s\n", strerror(errno));
	dbgprintf("   returning default RTO\n");
	return default_rto;
    }

    u_long bw = bandwidth();
    if (bw == 0) {
	return default_rto;
    }
    u_long rto = ((bufsize / bandwidth()) + 2 * RTT()) * 2;
    struct timeval tv = convert_to_timeval(rto);
    struct timespec ts_rto = {tv.tv_sec, tv.tv_usec * 1000};

    if (ts_rto.tv_sec < min_rto.tv_sec) {
	return min_rto;
    }
    return ts_rto;

    /*
    struct tcp_info info;
    socklen_t len = sizeof(info);
    struct protoent *pe = getprotobyname("TCP");
    int rc = -1;
    if (pe) {
	rc = getsockopt (osfd, pe->p_proto, TCP_INFO, &info, &len);
        if (rc == 0) {
            long int usecs = info.tcpi_rto;
            ret.tv_sec = usecs / 1000000;
            ret.tv_nsec = (usecs - (ret.tv_sec*1000000)) * 1000;
        } else {
            dbgprintf("getsockopt failed for TCP_INFO: %s\n",
                      strerror(errno));
        }
    } else {
        dbgprintf("getprotoent failed for TCP: %s\n",
                  strerror(errno));
    }
    if (rc < 0) {
	dbgprintf("Cannot read tcpi_rto; making a lazy guess\n");
        //TODO: more accurate guess?
    }
    dbgprintf("Retransmission timeout for csock %d is %ld.%09ld\n",
              osfd, ret.tv_sec, ret.tv_nsec);
    */
}

//#define useconds(tv) ((tv).tv_sec*1000000 + (tv).tv_usec)

ssize_t
CSocket::trickle_chunksize()/*struct timeval time_since_last_fg,
                              struct timeval bg_wait_time)*/
{
    const long int max_tolerable_fg_delay = 50; //ms
    ssize_t max_chunksize = (bandwidth() * max_tolerable_fg_delay) / 1000;
    //ssize_t min_chunksize = 64;
    /*
    ssize_t chunksize = min_chunksize * (1 << (useconds(time_since_last_fg) /
                                               useconds(sk->bg_wait_time())*2));
    if (chunksize < 0) {
        chunksize = max_chunksize;
    }
    */
    //ssize_t chunksize = max(chunksize, min_chunksize);
    ssize_t chunksize = max_chunksize;
    return chunksize;
}
<commit_msg>Minor compile (cast) fix.<commit_after>#include "cmm_socket.private.h"
#include "csocket.h"
#include "debug.h"
#include "timeops.h"
#include "cmm_socket_control.h"
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include "csocket_sender.h"
#include "csocket_receiver.h"
#include "csocket_mapping.h"
#include <functional>
using std::max;

CSocketPtr
CSocket::create(boost::weak_ptr<CMMSocketImpl> sk_,
                struct net_interface local_iface_,
                struct net_interface remote_iface_,
                int accepted_sock)
{
    CSocketPtr new_csock(new CSocket(sk_, local_iface_,
                                     remote_iface_, accepted_sock));
    new_csock->self_ptr = new_csock;
    return new_csock;
}

CSocket::CSocket(boost::weak_ptr<CMMSocketImpl> sk_,
                 struct net_interface local_iface_,
                 struct net_interface remote_iface_,
                 int accepted_sock)
    : sk(sk_),
      local_iface(local_iface_), remote_iface(remote_iface_),
      stats(local_iface, remote_iface),
      csock_sendr(NULL), csock_recvr(NULL), irob_indexes(local_iface_.labels)
{
    assert(sk);
    if (accepted_sock == -1) {
        osfd = socket(sk->sock_family, sk->sock_type, sk->sock_protocol);
        if (osfd < 0) {
            /* out of file descriptors or memory at this point */
            throw std::runtime_error("Out of FDs or memory!");
        }

        sk->set_all_sockopts(osfd);
    } else {
        osfd = accepted_sock;
    }

    int on = 1;
    int rc;
    /* Make sure that this socket is TCP_NODELAY for good performance */
    struct protoent *pe = getprotobyname("TCP");
    if (pe) {
	rc = setsockopt (osfd, pe->p_proto, TCP_NODELAY,
			 (char *) &on, sizeof(on));
    } else {
	rc = setsockopt (osfd, 6, TCP_NODELAY,
			 (char *) &on, sizeof(on));
    }
    if (rc < 0) {
	dbgprintf("Cannot make socket TCP_NODELAY");
    }
}

CSocket::~CSocket()
{
    dbgprintf("CSocket %d is being destroyed\n", osfd);
    if (osfd > 0) {
	/* if it's a real open socket */
        assert(csock_sendr == NULL && csock_recvr == NULL);
	close(osfd);
    }
}

int
CSocket::phys_connect()
{
    struct sockaddr_in local_addr, remote_addr;

    // XXX-TODO: don't assume it's an inet socket

    local_addr.sin_family = AF_INET;
    local_addr.sin_addr = local_iface.ip_addr;
    local_addr.sin_port = 0;

    remote_addr.sin_family = AF_INET;
    remote_addr.sin_addr = remote_iface.ip_addr;
    remote_addr.sin_port = sk->remote_listener_port;

    int rc = bind(osfd, (struct sockaddr *)&local_addr,
              sizeof(local_addr));
    if (rc < 0) {
	perror("bind");
	dbgprintf("Failed to bind osfd %d to %s:%d\n",
		  osfd, inet_ntoa(local_addr.sin_addr),
		  ntohs(local_addr.sin_port));
	return rc;
    }
    dbgprintf("Successfully bound osfd %d to %s:%d\n",
	      osfd, inet_ntoa(local_addr.sin_addr),
	      ntohs(local_addr.sin_port));

    rc = connect(osfd, (struct sockaddr *)&remote_addr,
		 sizeof(remote_addr));
    if (rc < 0) {
	perror("connect");
	dbgprintf("Failed to connect osfd %d to %s:%d\n",
		  osfd, inet_ntoa(remote_addr.sin_addr),
		  ntohs(remote_addr.sin_port));
	return rc;
    }
    struct CMMSocketControlHdr hdr;
    memset(&hdr, 0, sizeof(hdr));
    hdr.type = htons(CMM_CONTROL_MSG_NEW_INTERFACE);
    hdr.send_labels = 0;
    hdr.op.new_interface.ip_addr = local_iface.ip_addr;
    hdr.op.new_interface.labels = htonl(local_iface.labels);
    hdr.op.new_interface.bandwidth = htonl(local_iface.bandwidth);
    hdr.op.new_interface.RTT = htonl(local_iface.RTT);
    rc = send(osfd, &hdr, sizeof(hdr), 0);
    if (rc != sizeof(hdr)) {
        perror("send");
        dbgprintf("Failed to send interface info\n");
        return rc;
    }

    startup_workers();
    return 0;
}

void
CSocket::startup_workers()
{
    if (!csock_sendr && !csock_recvr) {
	csock_sendr = new CSocketSender(CSocketPtr(self_ptr));
	csock_recvr = new CSocketReceiver(CSocketPtr(self_ptr));
	int rc = csock_sendr->start();
        if (rc != 0) {
            throw std::runtime_error("Failed to create csocket_sender thread!");
        }
	rc = csock_recvr->start();
        if (rc != 0) {
            throw std::runtime_error("Failed to create csocket_receiver thread!");
        }
    }
}

/* must not be holding sk->scheduling_state_lock. */
bool
CSocket::matches(u_long send_labels)
{
    return sk->csock_map->csock_matches(this, send_labels);
}

u_long
CSocket::bandwidth()
{
    u_long bw_est;
    if (stats.get_estimate(NET_STATS_BW_UP, bw_est)) {
        return bw_est;
    } else {
        return iface_bandwidth(local_iface, remote_iface);
    }
}

double CSocket::RTT()
{
    u_long latency_est;
    if (stats.get_estimate(NET_STATS_LATENCY, latency_est)) {
        return (double)(latency_est * 2);
    } else {
        return iface_RTT(local_iface, remote_iface);
    }
}

struct timespec
CSocket::retransmission_timeout()
{
    // have a fairly high floor on this so that we don't
    //  flood the socket with spurious retransmissions
    struct timespec min_rto = {30, 0};
    struct timespec default_rto = {120, 0};

    int bufsize = 0;
    socklen_t len = sizeof(bufsize);
    int rc = getsockopt(osfd, SOL_SOCKET, SO_SNDBUF, &bufsize, &len);
    if (rc < 0) {
	dbgprintf("Failed to get socket send buffer size: %s\n", strerror(errno));
	dbgprintf("   returning default RTO\n");
	return default_rto;
    }

    u_long bw = bandwidth();
    if (bw == 0) {
	return default_rto;
    }
    u_long rto = ((bufsize / bandwidth()) + 2 * (u_long)RTT()) * 2;
    struct timeval tv = convert_to_timeval(rto);
    struct timespec ts_rto = {tv.tv_sec, tv.tv_usec * 1000};

    if (ts_rto.tv_sec < min_rto.tv_sec) {
	return min_rto;
    }
    return ts_rto;

    /*
    struct tcp_info info;
    socklen_t len = sizeof(info);
    struct protoent *pe = getprotobyname("TCP");
    int rc = -1;
    if (pe) {
	rc = getsockopt (osfd, pe->p_proto, TCP_INFO, &info, &len);
        if (rc == 0) {
            long int usecs = info.tcpi_rto;
            ret.tv_sec = usecs / 1000000;
            ret.tv_nsec = (usecs - (ret.tv_sec*1000000)) * 1000;
        } else {
            dbgprintf("getsockopt failed for TCP_INFO: %s\n",
                      strerror(errno));
        }
    } else {
        dbgprintf("getprotoent failed for TCP: %s\n",
                  strerror(errno));
    }
    if (rc < 0) {
	dbgprintf("Cannot read tcpi_rto; making a lazy guess\n");
        //TODO: more accurate guess?
    }
    dbgprintf("Retransmission timeout for csock %d is %ld.%09ld\n",
              osfd, ret.tv_sec, ret.tv_nsec);
    */
}

//#define useconds(tv) ((tv).tv_sec*1000000 + (tv).tv_usec)

ssize_t
CSocket::trickle_chunksize()/*struct timeval time_since_last_fg,
                              struct timeval bg_wait_time)*/
{
    const long int max_tolerable_fg_delay = 50; //ms
    ssize_t max_chunksize = (bandwidth() * max_tolerable_fg_delay) / 1000;
    //ssize_t min_chunksize = 64;
    /*
    ssize_t chunksize = min_chunksize * (1 << (useconds(time_since_last_fg) /
                                               useconds(sk->bg_wait_time())*2));
    if (chunksize < 0) {
        chunksize = max_chunksize;
    }
    */
    //ssize_t chunksize = max(chunksize, min_chunksize);
    ssize_t chunksize = max_chunksize;
    return chunksize;
}
<|endoftext|>