<commit_before>#define DEBUG_TYPE "dyn-aa"

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#include <string>
#include <cstdio>
#include <iostream>

#include "llvm/ADT/Statistic.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/raw_ostream.h"

#include "dyn-aa/Utils.h"
#include "dyn-aa/LogProcessor.h"

using namespace std;
using namespace llvm;
using namespace dyn_aa;

static cl::opt<string> LogFileName(
    "log-file",
    cl::desc("Point-to log file generated "
             "by running the instrumented program"));

STATISTIC(NumMemAllocRecords, "Number of memory allocation records");
STATISTIC(NumTopLevelRecords, "Number of top-level records");
STATISTIC(NumStoreRecords, "Number of store records");
STATISTIC(NumCallRecords, "Number of call records");
STATISTIC(NumReturnRecords, "Number of return records");
STATISTIC(NumRecords, "Number of all records");

// By default, these call-back functions do nothing.
void LogProcessor::processMemAlloc(const MemAllocRecord &) {
}
void LogProcessor::processTopLevel(const TopLevelRecord &) {
}
void LogProcessor::processStore(const StoreRecord &) {
}
void LogProcessor::processCall(const CallRecord &) {
}
void LogProcessor::processReturn(const ReturnRecord &) {
}

void LogProcessor::processLog(bool Reversed) {
  assert(LogFileName != "" && "Didn't specify the log file.");
  FILE *LogFile = fopen(LogFileName.c_str(), "rb");
  assert(LogFile && "The log file doesn't exist.");

  if (Reversed) {
    // Set the file position to the end.
    fseek(LogFile, 0, SEEK_END);
  }

  uint64_t FileSize = GetFileSize(LogFile);
  uint64_t NumBytesRead = 0;
  NumRecords = 0;
  CurrentRecordID = 0;
  DynAAUtils::PrintProgressBar(0, NumBytesRead, FileSize);
  LogRecord Record;
  while (ReadData(&Record, sizeof Record, Reversed, LogFile)) {
    uint64_t OldNumBytesRead = NumBytesRead;
    ++NumRecords;
    NumBytesRead += sizeof Record;
    switch (Record.RecordType) {
      case LogRecord::MemAlloc:
        processMemAlloc(Record.MAR);
        ++NumMemAllocRecords;
        break;
      case LogRecord::TopLevel:
        processTopLevel(Record.TLR);
        ++NumTopLevelRecords;
        break;
      case LogRecord::Store:
        processStore(Record.SR);
        ++NumStoreRecords;
        break;
      case LogRecord::Call:
        processCall(Record.CR);
        ++NumCallRecords;
        break;
      case LogRecord::Return:
        processReturn(Record.RR);
        ++NumReturnRecords;
        break;
    }
    ++CurrentRecordID;
    DynAAUtils::PrintProgressBar(OldNumBytesRead, NumBytesRead, FileSize);
  }
  errs() << "\n";

  assert(NumBytesRead == FileSize && "The file is not completely read.");

  fclose(LogFile);
}

bool LogProcessor::ReadData(void *P, int Length, bool Reversed, FILE *LogFile) {
  if (Reversed) {
    if (fseek(LogFile, -Length, SEEK_CUR) != 0) {
      return false;
    }
  }
  if (fread(P, Length, 1, LogFile) != 1) {
    return false;
  }
  if (Reversed) {
    fseek(LogFile, -Length, SEEK_CUR);
  }
  return true;
}

off_t LogProcessor::GetFileSize(FILE *LogFile) {
  int FD = fileno(LogFile);
  assert(FD != -1);
  struct stat StatBuf;
  int R = fstat(FD, &StatBuf);
  assert(R != -1);
  return StatBuf.st_size;
}
<commit_msg>Throw an warning when the log is broken<commit_after>#define DEBUG_TYPE "dyn-aa"

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#include <string>
#include <cstdio>
#include <iostream>

#include "llvm/ADT/Statistic.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/raw_ostream.h"

#include "dyn-aa/Utils.h"
#include "dyn-aa/LogProcessor.h"

using namespace std;
using namespace llvm;
using namespace dyn_aa;

static cl::opt<string> LogFileName(
    "log-file",
    cl::desc("Point-to log file generated "
             "by running the instrumented program"));

STATISTIC(NumMemAllocRecords, "Number of memory allocation records");
STATISTIC(NumTopLevelRecords, "Number of top-level records");
STATISTIC(NumStoreRecords, "Number of store records");
STATISTIC(NumCallRecords, "Number of call records");
STATISTIC(NumReturnRecords, "Number of return records");
STATISTIC(NumRecords, "Number of all records");

// By default, these call-back functions do nothing.
void LogProcessor::processMemAlloc(const MemAllocRecord &) {
}
void LogProcessor::processTopLevel(const TopLevelRecord &) {
}
void LogProcessor::processStore(const StoreRecord &) {
}
void LogProcessor::processCall(const CallRecord &) {
}
void LogProcessor::processReturn(const ReturnRecord &) {
}

void LogProcessor::processLog(bool Reversed) {
  assert(LogFileName != "" && "Didn't specify the log file.");
  FILE *LogFile = fopen(LogFileName.c_str(), "rb");
  assert(LogFile && "The log file doesn't exist.");

  if (Reversed) {
    // Set the file position to the end.
    fseek(LogFile, 0, SEEK_END);
  }

  uint64_t FileSize = GetFileSize(LogFile);
  uint64_t NumBytesRead = 0;
  NumRecords = 0;
  CurrentRecordID = 0;
  DynAAUtils::PrintProgressBar(0, NumBytesRead, FileSize);
  LogRecord Record;
  while (ReadData(&Record, sizeof Record, Reversed, LogFile)) {
    uint64_t OldNumBytesRead = NumBytesRead;
    ++NumRecords;
    NumBytesRead += sizeof Record;
    switch (Record.RecordType) {
      case LogRecord::MemAlloc:
        processMemAlloc(Record.MAR);
        ++NumMemAllocRecords;
        break;
      case LogRecord::TopLevel:
        processTopLevel(Record.TLR);
        ++NumTopLevelRecords;
        break;
      case LogRecord::Store:
        processStore(Record.SR);
        ++NumStoreRecords;
        break;
      case LogRecord::Call:
        processCall(Record.CR);
        ++NumCallRecords;
        break;
      case LogRecord::Return:
        processReturn(Record.RR);
        ++NumReturnRecords;
        break;
    }
    ++CurrentRecordID;
    DynAAUtils::PrintProgressBar(OldNumBytesRead, NumBytesRead, FileSize);
  }
  errs() << "\n";

  assert(NumBytesRead <= FileSize);
  if (NumBytesRead < FileSize) {
    errs().changeColor(raw_ostream::RED);
    errs() << "The log file is broken, probably because ";
    errs() << "the instrumented program might not exit normally. ";
    errs() << "Try to process as much log as possible.\n";
    errs().resetColor();
  }

  fclose(LogFile);
}

bool LogProcessor::ReadData(void *P, int Length, bool Reversed, FILE *LogFile) {
  if (Reversed) {
    if (fseek(LogFile, -Length, SEEK_CUR) != 0) {
      return false;
    }
  }
  if (fread(P, Length, 1, LogFile) != 1) {
    return false;
  }
  if (Reversed) {
    fseek(LogFile, -Length, SEEK_CUR);
  }
  return true;
}

off_t LogProcessor::GetFileSize(FILE *LogFile) {
  int FD = fileno(LogFile);
  assert(FD != -1);
  struct stat StatBuf;
  int R = fstat(FD, &StatBuf);
  assert(R != -1);
  return StatBuf.st_size;
}
<|endoftext|>


<commit_before>//===- PassManager.cpp - LLVM Pass Infrastructure Implementation ----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the LLVM Pass Manager infrastructure.
//
//===----------------------------------------------------------------------===//

#include "llvm/PassManager.h"
#include "llvm/Function.h"
#include "llvm/Module.h"

using namespace llvm;

// PassManagerAnalysisHelper implementation

/// Return TRUE IFF pass P's required analysis set does not required new
/// manager.
bool PassManagerAnalysisHelper::manageablePass(Pass *P) {

  AnalysisUsage AnUsage;
  P->getAnalysisUsage(AnUsage);

  // If this pass is not preserving information that is required by the other passes
  // managed by this manager then use new manager
  // TODO
  return true;
}

/// Return TRUE iff AnalysisID AID is currently available.
bool PassManagerAnalysisHelper::analysisCurrentlyAvailable(AnalysisID AID) {

  // TODO
  return false;
}

/// Augment RequiredSet by adding analysis required by pass P.
void PassManagerAnalysisHelper::noteDownRequiredAnalysis(Pass *P) {

  // TODO
}

/// Remove AnalysisID from the RequiredSet
void PassManagerAnalysisHelper::removeAnalysis(AnalysisID AID) {

  // TODO
}

/// Remove Analyss not preserved by Pass P
void PassManagerAnalysisHelper::removeNotPreservedAnalysis(Pass *P) {

  // TODO
}

/// BasicBlockPassManager implementation

/// Add pass P into PassVector and return TRUE. If this pass is not
/// manageable by this manager then return FALSE.
bool
BasicBlockPassManager_New::addPass (Pass *P) {

  BasicBlockPass *BP = dynamic_cast<BasicBlockPass*>(P);
  if (!BP)
    return false;

  // If this pass does not preserve anlysis that is used by other passes
  // managed by this manager than it is not a suiable pass for this manager.
  if (!manageablePass (P))
    return false;

  // Take a note of analysis required by this pass.
  noteDownRequiredAnalysis(P);

  // Add pass
  PassVector.push_back(BP);
  return true;
}

/// Execute all of the passes scheduled for execution by invoking
/// runOnBasicBlock method.  Keep track of whether any of the passes modifies
/// the function, and if so, return true.
bool
BasicBlockPassManager_New::runOnFunction(Function &F) {

  bool Changed = false;
  for (Function::iterator I = F.begin(), E = F.end(); I != E; ++I)
    for (std::vector<Pass *>::iterator itr = PassVector.begin(),
           e = PassVector.end(); itr != e; ++itr) {
      Pass *P = *itr;
      BasicBlockPass *BP = dynamic_cast<BasicBlockPass*>(P);
      Changed |= BP->runOnBasicBlock(*I);
    }
  return Changed;
}

// FunctionPassManager_New implementation

///////////////////////////////////////////////////////////////////////////////
// FunctionPassManager

/// Add pass P into the pass manager queue. If P is a BasicBlockPass then
/// either use it into active basic block pass manager or create new basic
/// block pass manager to handle pass P.
bool
FunctionPassManager_New::addPass (Pass *P) {

  // If P is a BasicBlockPass then use BasicBlockPassManager_New.
  if (BasicBlockPass *BP = dynamic_cast<BasicBlockPass*>(P)) {

    if (!activeBBPassManager
        || !activeBBPassManager->addPass(BP)) {

      activeBBPassManager = new BasicBlockPassManager_New();

      PassVector.push_back(activeBBPassManager);
      assert (!activeBBPassManager->addPass(BP) &&
              "Unable to add Pass");
    }
    return true;
  }

  FunctionPass *FP = dynamic_cast<FunctionPass *>(P);
  if (!FP)
    return false;

  // If this pass does not preserve anlysis that is used by other passes
  // managed by this manager than it is not a suiable pass for this manager.
  if (!manageablePass (P))
    return false;

  // Take a note of analysis required by this pass.
  noteDownRequiredAnalysis(P);

  PassVector.push_back(FP);
  activeBBPassManager = NULL;
  return true;
}

/// Execute all of the passes scheduled for execution by invoking
/// runOnFunction method.  Keep track of whether any of the passes modifies
/// the function, and if so, return true.
bool
FunctionPassManager_New::runOnModule(Module &M) {

  bool Changed = false;
  for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
    for (std::vector<Pass *>::iterator itr = PassVector.begin(),
           e = PassVector.end(); itr != e; ++itr) {
      Pass *P = *itr;
      FunctionPass *FP = dynamic_cast<FunctionPass*>(P);
      Changed |= FP->runOnFunction(*I);
    }
  return Changed;
}

// ModulePassManager implementation

/// Add P into pass vector if it is manageble. If P is a FunctionPass
/// then use FunctionPassManager_New to manage it. Return FALSE if P
/// is not manageable by this manager.
bool
ModulePassManager_New::addPass (Pass *P) {

  // If P is FunctionPass then use function pass maanager.
  if (FunctionPass *FP = dynamic_cast<FunctionPass*>(P)) {

    activeFunctionPassManager = NULL;

    if (!activeFunctionPassManager
        || !activeFunctionPassManager->addPass(P)) {

      activeFunctionPassManager = new FunctionPassManager_New();

      PassVector.push_back(activeFunctionPassManager);
      assert (!activeFunctionPassManager->addPass(FP) &&
              "Unable to add Pass");
    }
    return true;
  }

  ModulePass *MP = dynamic_cast<ModulePass *>(P);
  if (!MP)
    return false;

  // If this pass does not preserve anlysis that is used by other passes
  // managed by this manager than it is not a suiable pass for this manager.
  if (!manageablePass (P))
    return false;

  // Take a note of analysis required by this pass.
  noteDownRequiredAnalysis(P);

  PassVector.push_back(MP);
  activeFunctionPassManager = NULL;
  return true;
}

/// Execute all of the passes scheduled for execution by invoking
/// runOnModule method.  Keep track of whether any of the passes modifies
/// the module, and if so, return true.
bool
ModulePassManager_New::runOnModule(Module &M) {
  bool Changed = false;
  for (std::vector<Pass *>::iterator itr = PassVector.begin(),
         e = PassVector.end(); itr != e; ++itr) {
    Pass *P = *itr;
    ModulePass *MP = dynamic_cast<ModulePass*>(P);
    Changed |= MP->runOnModule(M);
  }
  return Changed;
}

/// Schedule all passes from the queue by adding them in their
/// respective manager's queue.
void
PassManager_New::schedulePasses() {
  /* TODO */
}

/// Add pass P to the queue of passes to run.
void
PassManager_New::add(Pass *P) {
  /* TODO */
}

// PassManager_New implementation
/// Add P into active pass manager or use new module pass manager to
/// manage it.
bool
PassManager_New::addPass (Pass *P) {

  if (!activeManager) {
    activeManager = new ModulePassManager_New();
    PassManagers.push_back(activeManager);
  }

  return activeManager->addPass(P);
}

/// run - Execute all of the passes scheduled for execution.  Keep track of
/// whether any of the passes modifies the module, and if so, return true.
bool
PassManager_New::run(Module &M) {

  schedulePasses();
  bool Changed = false;
  for (std::vector<ModulePassManager_New *>::iterator itr = PassManagers.begin(),
         e = PassManagers.end(); itr != e; ++itr) {
    ModulePassManager_New *pm = *itr;
    Changed |= pm->runOnModule(M);
  }
  return Changed;
}
<commit_msg>Beautify.<commit_after>//===- PassManager.cpp - LLVM Pass Infrastructure Implementation ----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by Devang Patel  and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the LLVM Pass Manager infrastructure.
//
//===----------------------------------------------------------------------===//

#include "llvm/PassManager.h"
#include "llvm/Module.h"

using namespace llvm;

// PassManagerAnalysisHelper implementation

/// Return true IFF pass P's required analysis set does not required new
/// manager.
bool PassManagerAnalysisHelper::manageablePass(Pass *P) {

  AnalysisUsage AnUsage;
  P->getAnalysisUsage(AnUsage);

  // If this pass is not preserving information that is required by the other passes
  // managed by this manager then use new manager
  // TODO
  return true;
}

/// Return true IFF AnalysisID AID is currently available.
bool PassManagerAnalysisHelper::analysisCurrentlyAvailable(AnalysisID AID) {

  // TODO
  return false;
}

/// Augment RequiredSet by adding analysis required by pass P.
void PassManagerAnalysisHelper::noteDownRequiredAnalysis(Pass *P) {

  // TODO
}

/// Remove AnalysisID from the RequiredSet
void PassManagerAnalysisHelper::removeAnalysis(AnalysisID AID) {

  // TODO
}

/// Remove Analyss not preserved by Pass P
void PassManagerAnalysisHelper::removeNotPreservedAnalysis(Pass *P) {

  // TODO
}

/// BasicBlockPassManager implementation

/// Add pass P into PassVector and return true. If this pass is not
/// manageable by this manager then return false.
bool
BasicBlockPassManager_New::addPass(Pass *P) {

  BasicBlockPass *BP = dynamic_cast<BasicBlockPass*>(P);
  if (!BP)
    return false;

  // If this pass does not preserve anlysis that is used by other passes
  // managed by this manager than it is not a suiable pass for this manager.
  if (!manageablePass(P))
    return false;

  // Take a note of analysis required by this pass.
  noteDownRequiredAnalysis(P);

  // Add pass
  PassVector.push_back(BP);
  return true;
}

/// Execute all of the passes scheduled for execution by invoking
/// runOnBasicBlock method.  Keep track of whether any of the passes modifies
/// the function, and if so, return true.
bool
BasicBlockPassManager_New::runOnFunction(Function &F) {

  bool Changed = false;
  for (Function::iterator I = F.begin(), E = F.end(); I != E; ++I)
    for (std::vector<Pass *>::iterator itr = PassVector.begin(),
           e = PassVector.end(); itr != e; ++itr) {
      Pass *P = *itr;
      BasicBlockPass *BP = dynamic_cast<BasicBlockPass*>(P);
      Changed |= BP->runOnBasicBlock(*I);
    }
  return Changed;
}

// FunctionPassManager_New implementation

// FunctionPassManager

/// Add pass P into the pass manager queue. If P is a BasicBlockPass then
/// either use it into active basic block pass manager or create new basic
/// block pass manager to handle pass P.
bool
FunctionPassManager_New::addPass(Pass *P) {

  // If P is a BasicBlockPass then use BasicBlockPassManager_New.
  if (BasicBlockPass *BP = dynamic_cast<BasicBlockPass*>(P)) {

    if (!activeBBPassManager
        || !activeBBPassManager->addPass(BP)) {

      activeBBPassManager = new BasicBlockPassManager_New();

      PassVector.push_back(activeBBPassManager);
      if (!activeBBPassManager->addPass(BP))
        assert(0 && "Unable to add Pass");
    }
    return true;
  }

  FunctionPass *FP = dynamic_cast<FunctionPass *>(P);
  if (!FP)
    return false;

  // If this pass does not preserve anlysis that is used by other passes
  // managed by this manager than it is not a suiable pass for this manager.
  if (!manageablePass(P))
    return false;

  // Take a note of analysis required by this pass.
  noteDownRequiredAnalysis(P);

  PassVector.push_back(FP);
  activeBBPassManager = NULL;
  return true;
}

/// Execute all of the passes scheduled for execution by invoking
/// runOnFunction method.  Keep track of whether any of the passes modifies
/// the function, and if so, return true.
bool
FunctionPassManager_New::runOnModule(Module &M) {

  bool Changed = false;
  for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
    for (std::vector<Pass *>::iterator itr = PassVector.begin(),
           e = PassVector.end(); itr != e; ++itr) {
      Pass *P = *itr;
      FunctionPass *FP = dynamic_cast<FunctionPass*>(P);
      Changed |= FP->runOnFunction(*I);
    }
  return Changed;
}

// ModulePassManager implementation

/// Add P into pass vector if it is manageble. If P is a FunctionPass
/// then use FunctionPassManager_New to manage it. Return false if P
/// is not manageable by this manager.
bool
ModulePassManager_New::addPass(Pass *P) {

  // If P is FunctionPass then use function pass maanager.
  if (FunctionPass *FP = dynamic_cast<FunctionPass*>(P)) {

    activeFunctionPassManager = NULL;

    if (!activeFunctionPassManager
        || !activeFunctionPassManager->addPass(P)) {

      activeFunctionPassManager = new FunctionPassManager_New();

      PassVector.push_back(activeFunctionPassManager);
      if (!activeFunctionPassManager->addPass(FP))
        assert(0 && "Unable to add pass");
    }
    return true;
  }

  ModulePass *MP = dynamic_cast<ModulePass *>(P);
  if (!MP)
    return false;

  // If this pass does not preserve anlysis that is used by other passes
  // managed by this manager than it is not a suiable pass for this manager.
  if (!manageablePass(P))
    return false;

  // Take a note of analysis required by this pass.
  noteDownRequiredAnalysis(P);

  PassVector.push_back(MP);
  activeFunctionPassManager = NULL;
  return true;
}

/// Execute all of the passes scheduled for execution by invoking
/// runOnModule method.  Keep track of whether any of the passes modifies
/// the module, and if so, return true.
bool
ModulePassManager_New::runOnModule(Module &M) {
  bool Changed = false;
  for (std::vector<Pass *>::iterator itr = PassVector.begin(),
         e = PassVector.end(); itr != e; ++itr) {
    Pass *P = *itr;
    ModulePass *MP = dynamic_cast<ModulePass*>(P);
    Changed |= MP->runOnModule(M);
  }
  return Changed;
}

/// Schedule all passes from the queue by adding them in their
/// respective manager's queue.
void
PassManager_New::schedulePasses() {
  /* TODO */
}

/// Add pass P to the queue of passes to run.
void
PassManager_New::add(Pass *P) {
  /* TODO */
}

// PassManager_New implementation
/// Add P into active pass manager or use new module pass manager to
/// manage it.
bool
PassManager_New::addPass(Pass *P) {

  if (!activeManager) {
    activeManager = new ModulePassManager_New();
    PassManagers.push_back(activeManager);
  }

  return activeManager->addPass(P);
}

/// run - Execute all of the passes scheduled for execution.  Keep track of
/// whether any of the passes modifies the module, and if so, return true.
bool
PassManager_New::run(Module &M) {

  schedulePasses();
  bool Changed = false;
  for (std::vector<ModulePassManager_New *>::iterator itr = PassManagers.begin(),
         e = PassManagers.end(); itr != e; ++itr) {
    ModulePassManager_New *pm = *itr;
    Changed |= pm->runOnModule(M);
  }
  return Changed;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <string>

#include <boost/program_options.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/foreach.hpp>

#include <amgcl/make_solver.hpp>
#include <amgcl/runtime.hpp>
#include <amgcl/relaxation/as_preconditioner.hpp>
#include <amgcl/preconditioner/schur_complement.hpp>
#include <amgcl/adapter/crs_tuple.hpp>
#include <amgcl/io/mm.hpp>
#include <amgcl/io/binary.hpp>
#include <amgcl/profiler.hpp>

namespace amgcl { profiler<> prof; }
using amgcl::prof;
using amgcl::precondition;

typedef amgcl::scoped_tic< amgcl::profiler<> > tic;

//---------------------------------------------------------------------------
template <class Matrix>
void solve_schur(const Matrix &K, const std::vector<double> &rhs, boost::property_tree::ptree &prm)
{
    tic t1(prof, "schur_complement");

    typedef amgcl::backend::builtin<double> Backend;

    typedef amgcl::make_solver<
        amgcl::relaxation::as_preconditioner<
            Backend, amgcl::relaxation::ilu0
            >,
        amgcl::solver::bicgstab<Backend>
        > USolver;

    typedef amgcl::make_solver<
        amgcl::amg<
            Backend,
            amgcl::coarsening::smoothed_aggregation,
            amgcl::relaxation::ilu0
            >,
        amgcl::solver::bicgstab<Backend>
        > PSolver;

    amgcl::make_solver<
        amgcl::preconditioner::schur_complement<USolver, PSolver>,
        amgcl::solver::bicgstab<Backend>
        > solve(K, prm);

    tic t2(prof, "solve");
    std::vector<double> x(rhs.size(), 1.0);

    size_t iters;
    double error;

    boost::tie(iters, error) = solve(rhs, x);

    std::cout << "Iterations: " << iters << std::endl
              << "Error:      " << error << std::endl;
}

//---------------------------------------------------------------------------
int main(int argc, char *argv[]) {
    using std::string;
    using std::vector;
    using amgcl::prof;
    using amgcl::precondition;

    namespace po = boost::program_options;
    namespace io = amgcl::io;

    po::options_description desc("Options");

    desc.add_options()
        ("help,h", "show help")
        (
         "binary,B",
         po::bool_switch()->default_value(false),
         "When specified, treat input files as binary instead of as MatrixMarket. "
         "It is assumed the files were converted to binary format with mm2bin utility. "
        )
        (
         "matrix,A",
         po::value<string>()->required(),
         "The system matrix in MatrixMarket format"
        )
        (
         "rhs,f",
         po::value<string>(),
         "The right-hand side in MatrixMarket format"
        )
        (
         "pmask,m",
         po::value<string>()->required(),
         "The pressure mask in MatrixMarket format. Or, if the parameter has "
         "the form '%n:m', then each (n+i*m)-th variable is treated as pressure."
        )
        (
         "params,P",
         po::value<string>(),
         "parameter file in json format"
        )
        (
         "prm,p",
         po::value< vector<string> >(),
         "Parameters specified as name=value pairs. "
         "May be provided multiple times. Examples:\n"
         "  -p solver.tol=1e-3\n"
         "  -p precond.coarse_enough=300"
        )
        ;

    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, desc), vm);

    if (vm.count("help")) {
        std::cout << desc << std::endl;
        return 0;
    }

    po::notify(vm);

    boost::property_tree::ptree prm;
    if (vm.count("params")) read_json(vm["params"].as<string>(), prm);

    if (vm.count("prm")) {
        BOOST_FOREACH(string pair, vm["prm"].as<vector<string> >())
        {
            using namespace boost::algorithm;
            vector<string> key_val;
            split(key_val, pair, is_any_of("="));
            if (key_val.size() != 2) throw po::invalid_option_value(
                    "Parameters specified with -p option "
                    "should have name=value format");

            prm.put(key_val[0], key_val[1]);
        }
    }

    size_t rows;
    vector<ptrdiff_t> ptr, col;
    vector<double> val, rhs;
    std::vector<char> pm;

    {
        tic t(prof, "reading");

        string Afile  = vm["matrix"].as<string>();
        bool   binary = vm["binary"].as<bool>();
        string mfile  = vm["pmask"].as<string>();

        if (binary) {
            io::read_crs(Afile, rows, ptr, col, val);
        } else {
            size_t cols;
            boost::tie(rows, cols) = io::mm_reader(Afile)(ptr, col, val);
            precondition(rows == cols, "Non-square system matrix");
        }

        if (vm.count("rhs")) {
            string bfile = vm["rhs"].as<string>();

            size_t n, m;

            if (binary) {
                io::read_dense(bfile, n, m, rhs);
            } else {
                boost::tie(n, m) = io::mm_reader(bfile)(rhs);
            }

            precondition(n == rows && m == 1, "The RHS vector has wrong size");
        } else {
            rhs.resize(rows, 1.0);
        }

        if (mfile[0] == '%') {
            int start  = std::atoi(mfile.substr(1).c_str());
            int stride = std::atoi(mfile.substr(3).c_str());
            pm.resize(rows, 0);
            for(size_t i = start; i < rows; i += stride) pm[i] = 1;
        } else {
            size_t n, m;

            if (binary) {
                io::read_dense(mfile, n, m, pm);
            } else {
                boost::tie(n, m) = amgcl::io::mm_reader(mfile)(pm);
            }

            precondition(n == rows && m == 1, "Mask file has wrong size");
        }
    }

    prm.put("precond.pmask", static_cast<void*>(&pm[0]));
    prm.put("precond.pmask_size", pm.size());

    solve_schur(boost::tie(rows, ptr, col, val), rhs, prm);

    std::cout << prof << std::endl;
}
<commit_msg>Use runtime interface in schur_complement<commit_after>#include <iostream>
#include <string>

#include <boost/program_options.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/foreach.hpp>

#include <amgcl/make_solver.hpp>
#include <amgcl/runtime.hpp>
#include <amgcl/relaxation/runtime.hpp>
#include <amgcl/preconditioner/schur_complement.hpp>
#include <amgcl/adapter/crs_tuple.hpp>
#include <amgcl/io/mm.hpp>
#include <amgcl/io/binary.hpp>
#include <amgcl/profiler.hpp>

namespace amgcl { profiler<> prof; }
using amgcl::prof;
using amgcl::precondition;

typedef amgcl::scoped_tic< amgcl::profiler<> > tic;

//---------------------------------------------------------------------------
template <class Matrix>
void solve_schur(const Matrix &K, const std::vector<double> &rhs, boost::property_tree::ptree &prm)
{
    tic t1(prof, "schur_complement");

    typedef amgcl::backend::builtin<double> Backend;

    typedef amgcl::make_solver<
        amgcl::runtime::relaxation::as_preconditioner<Backend>,
        amgcl::runtime::iterative_solver<Backend>
        > USolver;

    typedef amgcl::make_solver<
        amgcl::runtime::amg<Backend>,
        amgcl::runtime::iterative_solver<Backend>
        > PSolver;

    amgcl::make_solver<
        amgcl::preconditioner::schur_complement<USolver, PSolver>,
        amgcl::runtime::iterative_solver<Backend>
        > solve(K, prm);

    tic t2(prof, "solve");
    std::vector<double> x(rhs.size(), 1.0);

    size_t iters;
    double error;

    boost::tie(iters, error) = solve(rhs, x);

    std::cout << "Iterations: " << iters << std::endl
              << "Error:      " << error << std::endl;
}

//---------------------------------------------------------------------------
int main(int argc, char *argv[]) {
    using std::string;
    using std::vector;
    using amgcl::prof;
    using amgcl::precondition;

    namespace po = boost::program_options;
    namespace io = amgcl::io;

    po::options_description desc("Options");

    desc.add_options()
        ("help,h", "show help")
        (
         "binary,B",
         po::bool_switch()->default_value(false),
         "When specified, treat input files as binary instead of as MatrixMarket. "
         "It is assumed the files were converted to binary format with mm2bin utility. "
        )
        (
         "matrix,A",
         po::value<string>()->required(),
         "The system matrix in MatrixMarket format"
        )
        (
         "rhs,f",
         po::value<string>(),
         "The right-hand side in MatrixMarket format"
        )
        (
         "pmask,m",
         po::value<string>()->required(),
         "The pressure mask in MatrixMarket format. Or, if the parameter has "
         "the form '%n:m', then each (n+i*m)-th variable is treated as pressure."
        )
        (
         "params,P",
         po::value<string>(),
         "parameter file in json format"
        )
        (
         "prm,p",
         po::value< vector<string> >(),
         "Parameters specified as name=value pairs. "
         "May be provided multiple times. Examples:\n"
         "  -p solver.tol=1e-3\n"
         "  -p precond.coarse_enough=300"
        )
        ;

    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, desc), vm);

    if (vm.count("help")) {
        std::cout << desc << std::endl;
        return 0;
    }

    po::notify(vm);

    boost::property_tree::ptree prm;
    if (vm.count("params")) read_json(vm["params"].as<string>(), prm);

    if (vm.count("prm")) {
        BOOST_FOREACH(string pair, vm["prm"].as<vector<string> >())
        {
            using namespace boost::algorithm;
            vector<string> key_val;
            split(key_val, pair, is_any_of("="));
            if (key_val.size() != 2) throw po::invalid_option_value(
                    "Parameters specified with -p option "
                    "should have name=value format");

            prm.put(key_val[0], key_val[1]);
        }
    }

    size_t rows;
    vector<ptrdiff_t> ptr, col;
    vector<double> val, rhs;
    std::vector<char> pm;

    {
        tic t(prof, "reading");

        string Afile  = vm["matrix"].as<string>();
        bool   binary = vm["binary"].as<bool>();
        string mfile  = vm["pmask"].as<string>();

        if (binary) {
            io::read_crs(Afile, rows, ptr, col, val);
        } else {
            size_t cols;
            boost::tie(rows, cols) = io::mm_reader(Afile)(ptr, col, val);
            precondition(rows == cols, "Non-square system matrix");
        }

        if (vm.count("rhs")) {
            string bfile = vm["rhs"].as<string>();

            size_t n, m;

            if (binary) {
                io::read_dense(bfile, n, m, rhs);
            } else {
                boost::tie(n, m) = io::mm_reader(bfile)(rhs);
            }

            precondition(n == rows && m == 1, "The RHS vector has wrong size");
        } else {
            rhs.resize(rows, 1.0);
        }

        if (mfile[0] == '%') {
            int start  = std::atoi(mfile.substr(1).c_str());
            int stride = std::atoi(mfile.substr(3).c_str());
            pm.resize(rows, 0);
            for(size_t i = start; i < rows; i += stride) pm[i] = 1;
        } else {
            size_t n, m;

            if (binary) {
                io::read_dense(mfile, n, m, pm);
            } else {
                boost::tie(n, m) = amgcl::io::mm_reader(mfile)(pm);
            }

            precondition(n == rows && m == 1, "Mask file has wrong size");
        }
    }

    prm.put("precond.pmask", static_cast<void*>(&pm[0]));
    prm.put("precond.pmask_size", pm.size());

    solve_schur(boost::tie(rows, ptr, col, val), rhs, prm);

    std::cout << prof << std::endl;
}
<|endoftext|>


<commit_before><commit_msg>coverity#707771 coverity gold, Uninitialized m_refCount<commit_after><|endoftext|>


<commit_before>#include "SM_Matrix2D.h"
#include "SM_Math.h"

#include <string.h>

namespace sm
{

Matrix2D::Matrix2D()
{
	Identity();
}

Matrix2D::Matrix2D(const Matrix2D& mt)
{
	memcpy(x, mt.x, sizeof(x));
}

Matrix2D& Matrix2D::operator = (const Matrix2D& mt)
{
	memcpy(x, mt.x, sizeof(x));
	return *this;
}

static inline Matrix2D
inverse_scale(const Matrix2D& m)
{
	Matrix2D ret;
	if (m.x[0] == 0 || m.x[3] == 0) {
		return ret;
	}

	ret.x[0] = 1 / m.x[0];
	ret.x[1] = 0;
	ret.x[2] = 0;
	ret.x[3] = 1 / m.x[3];
	ret.x[4] = - m.x[4] * ret.x[0];
	ret.x[5] = - m.x[5] * ret.x[3];

	return ret;
}

static inline Matrix2D
inverse_rot(const Matrix2D& m)
{
	Matrix2D ret;
	if (m.x[1] == 0 || m.x[2] == 0) {
		return ret;
	}

	ret.x[0] = 0;
	ret.x[1] = 1 / m.x[2];
	ret.x[2] = 1 / m.x[1];
	ret.x[3] = 0;
	ret.x[4] = - m.x[5] * ret.x[2];
	ret.x[5] = - m.x[4] * ret.x[1];

	return ret;
}

Matrix2D Matrix2D::Inverted() const
{
	if (x[1] == 0 && x[2] == 0) {
		return inverse_scale(*this);
	}
	if (x[0] == 0 && x[3] == 0) {
		return inverse_rot(*this);
	}

	Matrix2D ret;
	int t = x[0] * x[3] - x[1] * x[2] ;
	if (t == 0) {
		return ret;
	}

	ret.x[0] =   x[3] / t;
	ret.x[1] = - x[1] / t;
	ret.x[2] = - x[2] / t;
	ret.x[3] =   x[0] / t;
	ret.x[4] = - (x[4] * ret.x[0] + x[5] * ret.x[2]);
	ret.x[5] = - (x[4] * ret.x[1] + x[5] * ret.x[3]);

	return ret;
}

void Matrix2D::Shear(float kx, float ky)
{
	Matrix2D m = *this;
	x[0] = m.x[0] + m.x[1] * ky;
	x[1] = m.x[0] * kx + m.x[1];
	x[2] = m.x[2] + m.x[3] * ky;
	x[3] = m.x[2] * kx + m.x[3];
	x[4] = m.x[4] + m.x[5] * ky;
	x[5] = m.x[4] * kx + m.x[5];
}

void Matrix2D::Scale(float sx, float sy)
{
	if (sx != 1) {
		x[0] *= sx;
		x[2] *= sx;
		x[4] *= sx;
	}
	if (sy != 1) {
		x[1] *= sy;
		x[3] *= sy;
		x[5] *= sy;
	}
}

void Matrix2D::Rotate(float rotate)
{
	if (rotate == 0) {
		return;
	}

	int cosd = cosf(rotate);
	int sind = sinf(rotate);

	int m0_cosd = x[0] * cosd;
	int m0_sind = x[0] * sind;
	int m1_cosd = x[1] * cosd;
	int m1_sind = x[1] * sind;
	int m2_cosd = x[2] * cosd;
	int m2_sind = x[2] * sind;
	int m3_cosd = x[3] * cosd;
	int m3_sind = x[3] * sind;
	int m4_cosd = x[4] * cosd;
	int m4_sind = x[4] * sind;
	int m5_cosd = x[5] * cosd;
	int m5_sind = x[5] * sind;

	x[0] = m0_cosd - m1_sind;
	x[1] = m0_sind + m1_cosd;
	x[2] = m2_cosd - m3_sind;
	x[3] = m2_sind + m3_cosd;
	x[4] = m4_cosd - m5_sind;
	x[5] = m4_sind + m5_cosd;
}

void Matrix2D::Translate(float _x, float _y)
{
	x[4] += _x;
	x[5] += _y;
}

void Matrix2D::SetTransformation(float _x, float _y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
{
	float c = sm::cos(angle), s = sm::sin(angle);
	// matrix multiplication carried out on paper:
	// |1   x| |c -s  | |sx     | | 1 ky  | |1   -ox|
	// |  1 y| |s  c  | |   sy  | |kx  1  | |  1 -oy|
	//  move     rotate   scale     skew      origin
	x[0]  = c * sx - ky * s * sy; // = a
	x[1]  = s * sx + ky * c * sy; // = b
	x[2]  = kx * c * sx - s * sy; // = c
	x[3]  = kx * s * sx + c * sy; // = d
	x[4] = _x - ox * x[0] - oy * x[2];
	x[5] = _y - ox * x[1] - oy * x[3];
}

}
<commit_msg>[FIXED] Matrix2D::Shear()<commit_after>#include "SM_Matrix2D.h"
#include "SM_Math.h"

#include <string.h>

namespace sm
{

Matrix2D::Matrix2D()
{
	Identity();
}

Matrix2D::Matrix2D(const Matrix2D& mt)
{
	memcpy(x, mt.x, sizeof(x));
}

Matrix2D& Matrix2D::operator = (const Matrix2D& mt)
{
	memcpy(x, mt.x, sizeof(x));
	return *this;
}

static inline Matrix2D
inverse_scale(const Matrix2D& m)
{
	Matrix2D ret;
	if (m.x[0] == 0 || m.x[3] == 0) {
		return ret;
	}

	ret.x[0] = 1 / m.x[0];
	ret.x[1] = 0;
	ret.x[2] = 0;
	ret.x[3] = 1 / m.x[3];
	ret.x[4] = - m.x[4] * ret.x[0];
	ret.x[5] = - m.x[5] * ret.x[3];

	return ret;
}

static inline Matrix2D
inverse_rot(const Matrix2D& m)
{
	Matrix2D ret;
	if (m.x[1] == 0 || m.x[2] == 0) {
		return ret;
	}

	ret.x[0] = 0;
	ret.x[1] = 1 / m.x[2];
	ret.x[2] = 1 / m.x[1];
	ret.x[3] = 0;
	ret.x[4] = - m.x[5] * ret.x[2];
	ret.x[5] = - m.x[4] * ret.x[1];

	return ret;
}

Matrix2D Matrix2D::Inverted() const
{
	if (x[1] == 0 && x[2] == 0) {
		return inverse_scale(*this);
	}
	if (x[0] == 0 && x[3] == 0) {
		return inverse_rot(*this);
	}

	Matrix2D ret;
	int t = x[0] * x[3] - x[1] * x[2] ;
	if (t == 0) {
		return ret;
	}

	ret.x[0] =   x[3] / t;
	ret.x[1] = - x[1] / t;
	ret.x[2] = - x[2] / t;
	ret.x[3] =   x[0] / t;
	ret.x[4] = - (x[4] * ret.x[0] + x[5] * ret.x[2]);
	ret.x[5] = - (x[4] * ret.x[1] + x[5] * ret.x[3]);

	return ret;
}

void Matrix2D::Shear(float kx, float ky)
{
	Matrix2D m = *this;
	x[0] = m.x[0] + m.x[1] * kx;
	x[1] = m.x[0] * ky + m.x[1];
	x[2] = m.x[2] + m.x[3] * kx;
	x[3] = m.x[2] * ky + m.x[3];
	x[4] = m.x[4] + m.x[5] * kx;
	x[5] = m.x[4] * ky + m.x[5];

}

void Matrix2D::Scale(float sx, float sy)
{
	if (sx != 1) {
		x[0] *= sx;
		x[2] *= sx;
		x[4] *= sx;
	}
	if (sy != 1) {
		x[1] *= sy;
		x[3] *= sy;
		x[5] *= sy;
	}
}

void Matrix2D::Rotate(float rotate)
{
	if (rotate == 0) {
		return;
	}

	int cosd = cosf(rotate);
	int sind = sinf(rotate);

	int m0_cosd = x[0] * cosd;
	int m0_sind = x[0] * sind;
	int m1_cosd = x[1] * cosd;
	int m1_sind = x[1] * sind;
	int m2_cosd = x[2] * cosd;
	int m2_sind = x[2] * sind;
	int m3_cosd = x[3] * cosd;
	int m3_sind = x[3] * sind;
	int m4_cosd = x[4] * cosd;
	int m4_sind = x[4] * sind;
	int m5_cosd = x[5] * cosd;
	int m5_sind = x[5] * sind;

	x[0] = m0_cosd - m1_sind;
	x[1] = m0_sind + m1_cosd;
	x[2] = m2_cosd - m3_sind;
	x[3] = m2_sind + m3_cosd;
	x[4] = m4_cosd - m5_sind;
	x[5] = m4_sind + m5_cosd;
}

void Matrix2D::Translate(float _x, float _y)
{
	x[4] += _x;
	x[5] += _y;
}

void Matrix2D::SetTransformation(float _x, float _y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
{
	float c = sm::cos(angle), s = sm::sin(angle);
	// matrix multiplication carried out on paper:
	// |1   x| |c -s  | |sx     | | 1 ky  | |1   -ox|
	// |  1 y| |s  c  | |   sy  | |kx  1  | |  1 -oy|
	//  move     rotate   scale     skew      origin
	x[0]  = c * sx - ky * s * sy; // = a
	x[1]  = s * sx + ky * c * sy; // = b
	x[2]  = kx * c * sx - s * sy; // = c
	x[3]  = kx * s * sx + c * sy; // = d
	x[4] = _x - ox * x[0] - oy * x[2];
	x[5] = _y - ox * x[1] - oy * x[3];
}

}
<|endoftext|>


<commit_before>#include <iostream>
#include <string>

#include <boost/program_options.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>

#include <amgcl/make_solver.hpp>
#include <amgcl/runtime.hpp>
#include <amgcl/relaxation/runtime.hpp>
#include <amgcl/preconditioner/cpr.hpp>
#include <amgcl/preconditioner/simple.hpp>
#include <amgcl/adapter/crs_tuple.hpp>
#include <amgcl/io/mm.hpp>
#include <amgcl/profiler.hpp>

namespace amgcl {
    profiler<> prof;
} // namespace amgcl

//---------------------------------------------------------------------------
int main(int argc, char *argv[]) {
    using amgcl::prof;
    using amgcl::precondition;

    // Read configuration from command line
    std::string parameter_file;
    std::string A_file;
    std::string pm_file;
    std::string rhs_file;
    std::string out_file = "out.mtx";
    amgcl::runtime::coarsening::type coarsening = amgcl::runtime::coarsening::smoothed_aggregation;
    amgcl::runtime::relaxation::type prelax     = amgcl::runtime::relaxation::spai0;
    amgcl::runtime::relaxation::type frelax     = amgcl::runtime::relaxation::ilu0;
    amgcl::runtime::solver::type     solver     = amgcl::runtime::solver::bicgstab;

    namespace po = boost::program_options;
    po::options_description desc("Options");

    desc.add_options()
        ("help,h", "show help")
        (
         "params,p",
         po::value<std::string>(&parameter_file),
         "parameter file in json format"
        )
        (
         "matrix,A",
         po::value<std::string>(&A_file)->required(),
         "The system matrix in MatrixMarket format"
        )
        (
         "pmask,m",
         po::value<std::string>(&pm_file)->required(),
         "The pressure mask in MatrixMarket format"
        )
        (
         "rhs,b",
         po::value<std::string>(&rhs_file),
         "The right-hand side in MatrixMarket format"
        )
        (
         "coarsening,c",
         po::value<amgcl::runtime::coarsening::type>(&coarsening)->default_value(coarsening),
         "ruge_stuben, aggregation, smoothed_aggregation, smoothed_aggr_emin"
        )
        (
         "pressure_relaxation,r",
         po::value<amgcl::runtime::relaxation::type>(&prelax)->default_value(prelax),
         "gauss_seidel, multicolor_gauss_seidel, ilu0, damped_jacobi, spai0, chebyshev"
        )
        (
         "flow_relaxation,f",
         po::value<amgcl::runtime::relaxation::type>(&frelax)->default_value(frelax),
         "gauss_seidel, multicolor_gauss_seidel, ilu0, damped_jacobi, spai0, chebyshev"
        )
        (
         "solver,s",
         po::value<amgcl::runtime::solver::type>(&solver)->default_value(solver),
         "cg, bicgstab, bicgstabl, gmres"
        )
        (
         "output,o",
         po::value<std::string>(&out_file),
         "The output file (saved in MatrixMarket format)"
        )
        ;

    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, desc), vm);

    if (vm.count("help")) {
        std::cout << desc << std::endl;
        return 0;
    }

    po::notify(vm);

    // Read the matrix and the right-hand side.
    prof.tic("read");
    size_t rows, cols;
    std::vector<int> ptr, col;
    std::vector<double> val;
    boost::tie(rows, cols) = amgcl::io::mm_reader(A_file)(ptr, col, val);

    std::vector<char> pm;
    {
        size_t n, m;
        boost::tie(n, m) = amgcl::io::mm_reader(pm_file)(pm);
    }

    std::vector<double> rhs;
    if (vm.count("rhs")) {
        size_t n, m;
        boost::tie(n, m) = amgcl::io::mm_reader(rhs_file)(rhs);
    } else {
        std::cout << "RHS was not provided; using default value of 1" << std::endl;
        rhs.resize(rows, 1.0);
    }

    precondition(rows == rhs.size(), "Matrix and RHS sizes differ");

    boost::property_tree::ptree prm;
    if (vm.count("params")) read_json(parameter_file, prm);

    prm.put("precond.pressure.coarsening.type", coarsening);
    prm.put("precond.pressure.relaxation.type", prelax);
    prm.put("precond.flow.type", frelax);
    prm.put("precond.pmask", static_cast<void*>(&pm[0]));
    prm.put("precond.pmask_size", pm.size());
    prm.put("solver.type", solver);

    prof.toc("read");

    // Setup CPR preconditioner
    prof.tic("setup");
    prof.tic("cpr");
    amgcl::make_solver<
        amgcl::preconditioner::cpr<
            amgcl::runtime::amg<
                amgcl::backend::builtin<double>
                >,
            amgcl::runtime::relaxation::as_preconditioner<
                amgcl::backend::builtin<double>
                >
            >,
        amgcl::runtime::iterative_solver<
            amgcl::backend::builtin<double>
            >
        > cpr( boost::tie(rows, ptr, col, val), prm );
    prof.toc("cpr");

    prof.tic("simple");
    amgcl::make_solver<
        amgcl::preconditioner::simple<
            amgcl::runtime::amg<
                amgcl::backend::builtin<double>
                >,
            amgcl::runtime::relaxation::as_preconditioner<
                amgcl::backend::builtin<double>
                >
            >,
        amgcl::runtime::iterative_solver<
            amgcl::backend::builtin<double>
            >
        > simple( boost::tie(rows, ptr, col, val), prm );
    prof.toc("simple");
    prof.toc("setup");

    // Solve the problem
    std::vector<double> x(rows);

    size_t iters;
    double resid;

    prof.tic("solve");
    boost::fill(x, 0);

    prof.tic("cpr");
    boost::tie(iters, resid) = cpr(rhs, x);
    prof.toc("cpr");

    std::cout << "CPR:" << std::endl
              << "  Iterations:     " << iters << std::endl
              << "  Reported Error: " << resid << std::endl
              << std::endl;

    boost::fill(x, 0);

    prof.tic("simple");
    boost::tie(iters, resid) = simple(rhs, x);
    prof.toc("simple");

    std::cout << "SIMPLE:" << std::endl
              << "  Iterations:     " << iters << std::endl
              << "  Reported Error: " << resid << std::endl
              << std::endl;
    prof.toc("solve");

    std::cout << prof << std::endl;
}
<commit_msg>Simplify specification of pressure mask in two_step_precond<commit_after>#include <iostream>
#include <string>

#include <boost/program_options.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>

#include <amgcl/make_solver.hpp>
#include <amgcl/runtime.hpp>
#include <amgcl/relaxation/runtime.hpp>
#include <amgcl/preconditioner/cpr.hpp>
#include <amgcl/preconditioner/simple.hpp>
#include <amgcl/adapter/crs_tuple.hpp>
#include <amgcl/io/mm.hpp>
#include <amgcl/profiler.hpp>

namespace amgcl {
    profiler<> prof;
} // namespace amgcl

//---------------------------------------------------------------------------
int main(int argc, char *argv[]) {
    using amgcl::prof;
    using amgcl::precondition;

    // Read configuration from command line
    std::string parameter_file;
    std::string A_file;
    std::string pm_file;
    std::string rhs_file;
    std::string out_file = "out.mtx";
    amgcl::runtime::coarsening::type coarsening = amgcl::runtime::coarsening::smoothed_aggregation;
    amgcl::runtime::relaxation::type prelax     = amgcl::runtime::relaxation::spai0;
    amgcl::runtime::relaxation::type frelax     = amgcl::runtime::relaxation::ilu0;
    amgcl::runtime::solver::type     solver     = amgcl::runtime::solver::bicgstab;

    namespace po = boost::program_options;
    po::options_description desc("Options");

    desc.add_options()
        ("help,h", "show help")
        (
         "params,p",
         po::value<std::string>(&parameter_file),
         "parameter file in json format"
        )
        (
         "matrix,A",
         po::value<std::string>(&A_file)->required(),
         "The system matrix in MatrixMarket format"
        )
        (
         "pmask,m",
         po::value<std::string>(&pm_file)->required(),
         "The pressure mask in MatrixMarket format. Or, if the parameter has "
         "the form '%n', then each n-th variable is treated as pressure."
        )
        (
         "rhs,b",
         po::value<std::string>(&rhs_file),
         "The right-hand side in MatrixMarket format"
        )
        (
         "coarsening,c",
         po::value<amgcl::runtime::coarsening::type>(&coarsening)->default_value(coarsening),
         "ruge_stuben, aggregation, smoothed_aggregation, smoothed_aggr_emin"
        )
        (
         "pressure_relaxation,r",
         po::value<amgcl::runtime::relaxation::type>(&prelax)->default_value(prelax),
         "gauss_seidel, multicolor_gauss_seidel, ilu0, damped_jacobi, spai0, chebyshev"
        )
        (
         "flow_relaxation,f",
         po::value<amgcl::runtime::relaxation::type>(&frelax)->default_value(frelax),
         "gauss_seidel, multicolor_gauss_seidel, ilu0, damped_jacobi, spai0, chebyshev"
        )
        (
         "solver,s",
         po::value<amgcl::runtime::solver::type>(&solver)->default_value(solver),
         "cg, bicgstab, bicgstabl, gmres"
        )
        (
         "output,o",
         po::value<std::string>(&out_file),
         "The output file (saved in MatrixMarket format)"
        )
        ;

    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, desc), vm);

    if (vm.count("help")) {
        std::cout << desc << std::endl;
        return 0;
    }

    po::notify(vm);

    // Read the matrix and the right-hand side.
    prof.tic("read");
    size_t rows, cols;
    std::vector<int> ptr, col;
    std::vector<double> val;
    boost::tie(rows, cols) = amgcl::io::mm_reader(A_file)(ptr, col, val);

    std::vector<char> pm;
    if (pm_file[0] == '%') {
        int stride = std::atoi(pm_file.substr(1).c_str());
        pm.resize(rows, 0);
        for(size_t i = 0; i < rows; i += stride) pm[i] = 1;
    } else {
        size_t n, m;
        boost::tie(n, m) = amgcl::io::mm_reader(pm_file)(pm);
    }

    std::vector<double> rhs;
    if (vm.count("rhs")) {
        size_t n, m;
        boost::tie(n, m) = amgcl::io::mm_reader(rhs_file)(rhs);
    } else {
        std::cout << "RHS was not provided; using default value of 1" << std::endl;
        rhs.resize(rows, 1.0);
    }

    precondition(rows == rhs.size(), "Matrix and RHS sizes differ");

    boost::property_tree::ptree prm;
    if (vm.count("params")) read_json(parameter_file, prm);

    prm.put("precond.pressure.coarsening.type", coarsening);
    prm.put("precond.pressure.relaxation.type", prelax);
    prm.put("precond.flow.type", frelax);
    prm.put("precond.pmask", static_cast<void*>(&pm[0]));
    prm.put("precond.pmask_size", pm.size());
    prm.put("solver.type", solver);

    prof.toc("read");

    // Setup CPR preconditioner
    prof.tic("setup");
    prof.tic("cpr");
    amgcl::make_solver<
        amgcl::preconditioner::cpr<
            amgcl::runtime::amg<
                amgcl::backend::builtin<double>
                >,
            amgcl::runtime::relaxation::as_preconditioner<
                amgcl::backend::builtin<double>
                >
            >,
        amgcl::runtime::iterative_solver<
            amgcl::backend::builtin<double>
            >
        > cpr( boost::tie(rows, ptr, col, val), prm );
    prof.toc("cpr");

    prof.tic("simple");
    amgcl::make_solver<
        amgcl::preconditioner::simple<
            amgcl::runtime::amg<
                amgcl::backend::builtin<double>
                >,
            amgcl::runtime::relaxation::as_preconditioner<
                amgcl::backend::builtin<double>
                >
            >,
        amgcl::runtime::iterative_solver<
            amgcl::backend::builtin<double>
            >
        > simple( boost::tie(rows, ptr, col, val), prm );
    prof.toc("simple");
    prof.toc("setup");

    // Solve the problem
    std::vector<double> x(rows);

    size_t iters;
    double resid;

    prof.tic("solve");
    boost::fill(x, 0);

    prof.tic("cpr");
    boost::tie(iters, resid) = cpr(rhs, x);
    prof.toc("cpr");

    std::cout << "CPR:" << std::endl
              << "  Iterations:     " << iters << std::endl
              << "  Reported Error: " << resid << std::endl
              << std::endl;

    boost::fill(x, 0);

    prof.tic("simple");
    boost::tie(iters, resid) = simple(rhs, x);
    prof.toc("simple");

    std::cout << "SIMPLE:" << std::endl
              << "  Iterations:     " << iters << std::endl
              << "  Reported Error: " << resid << std::endl
              << std::endl;
    prof.toc("solve");

    std::cout << prof << std::endl;
}
<|endoftext|>


<commit_before>/*****************************************************************************
** Copyright (C) 2011 Connected Table AB
**
** An epoll based event dispatcher for Qt.
**
** Notable work by Steffen Hansen and Tobias Nätterlund of KDAB
******************************************************************************/

#include <qplatformdefs.h>

#include <qcoreapplication.h>
#include <qpair.h>
#include <qsocketnotifier.h>
#include <qthread.h>
#include <qelapsedtimer.h>

#include "qeventdispatcher_epoll.h"
#include <private/qthread_p.h>
#include <private/qcoreapplication_p.h>
#include <private/qcore_unix_p.h>

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/epoll.h>

#include <QDebug>

QT_BEGIN_NAMESPACE

/*****************************************************************************
 UNIX signal handling
 *****************************************************************************/

QEventDispatcherEpollPrivate::QEventDispatcherEpollPrivate()
{
    epollFD = epoll_create(16384);
//    qDebug() << "epollFD =" << epollFD;

    //mainThread = (QThread::currentThread() == QCoreApplication::instance()->thread());
    mainThread = true;
    bool pipefail = false;

    // initialize the common parts of the event loop
    if (qt_safe_pipe(thread_pipe, O_NONBLOCK) == -1) {
        perror("QEventDispatcherUNIXPrivate(): Unable to create thread pipe");
        pipefail = true;
    }

    if (pipefail)
        qFatal("QEventDispatcherUNIXPrivate(): Can not continue without a thread pipe");

    epoll_event ev;
    memset(&ev,0,sizeof(ev));
    ev.data.fd = thread_pipe[0];
    ev.events = EPOLLIN;//| EPOLLOUT | EPOLLPRI;
    int rc = epoll_ctl(epollFD, EPOLL_CTL_ADD, thread_pipe[0], &ev);
    if( rc != 0 ) perror("QEventDispatcherEpollPrivate::doSelect(), epoll_ctl failed: ");

    //sn_highest = -1;

    interrupt = false;
}

QEventDispatcherEpollPrivate::~QEventDispatcherEpollPrivate()
{
    // cleanup the common parts of the event loop
    close(thread_pipe[0]);
    close(thread_pipe[1]);

    close(epollFD);

    // cleanup timers
    qDeleteAll(timerList);
}

#define EVENT_COUNT 100

int QEventDispatcherEpollPrivate::doSelect(QEventLoop::ProcessEventsFlags flags, timeval *timeout)
{
    Q_Q(QEventDispatcherEpoll);

//    qDebug() << "QEventDispatcherEpollPrivate::doSelect(" << flags << timeout << ")";

    // needed in QEventDispatcherUNIX::select()
    timerList.updateCurrentTime();

    int nsel = 0;
    epoll_event events[EVENT_COUNT];
    memset(events,0,sizeof(epoll_event)*EVENT_COUNT);
    int nevents = 0;
    do {
        if(timeout)
            nsel = epoll_wait(epollFD, events, EVENT_COUNT, timeout->tv_sec * 1000 + timeout->tv_usec / 1000);
        else // timeout == NULL means wait indefinitely for select(), -1 does the same for epoll_wait()
            nsel = epoll_wait(epollFD, events, EVENT_COUNT, -1);
        //qDebug() << "nsel after epoll_wait =" << nsel;
    } while (nsel == -1 && (errno == EINTR || errno == EAGAIN));

    if (nsel == -1) {
        if (errno == EBADF) {
            // it seems a socket notifier has a bad fd... find out
            // which one it is and disable it
            qWarning("EBADF handling not implemented!");
            // TODO
        } else {
            // EINVAL... shouldn't happen, so let's complain to stderr
            // and hope someone sends us a bug report
            perror("epoll_wait()");
        }
    }

    // some other thread woke us up... consume the data on the thread pipe so that
    // select doesn't immediately return next time
    for(int i = 0; i < nsel; ++i) {
        if(events[i].data.fd == thread_pipe[0]) {
            //qDebug("Reading thread_pipe[0]");
            char c[16];
            while (::read(thread_pipe[0], c, sizeof(c)) > 0)
                ;
            if (!wakeUps.testAndSetRelease(1, 0)) {
                // hopefully, this is dead code
                qWarning("QEventDispatcherUNIX: internal error, wakeUps.testAndSetRelease(1, 0) failed!");
            }
            ++nevents;
            break;
        }
    }

    // activate socket notifiers
    if(! (flags & QEventLoop::ExcludeSocketNotifiers) && nsel > 0)
        return nevents + q->activateSocketNotifiers(nsel, events);
    else
        return nevents;
}

QEventDispatcherEpoll::QEventDispatcherEpoll(QObject *parent)
    : QAbstractEventDispatcher(*new QEventDispatcherEpollPrivate, parent)
{ }

QEventDispatcherEpoll::QEventDispatcherEpoll(QEventDispatcherEpollPrivate &dd, QObject *parent)
    : QAbstractEventDispatcher(dd, parent)
{ }

QEventDispatcherEpoll::~QEventDispatcherEpoll()
{
    Q_D(QEventDispatcherEpoll);
    d->threadData->eventDispatcher = 0;
}

/*!
    \internal
*/
void QEventDispatcherEpoll::registerTimer(int timerId, int interval, QObject *obj)
{
#ifndef QT_NO_DEBUG
    if (timerId < 1 || interval < 0 || !obj) {
        qWarning("QEventDispatcherUNIX::registerTimer: invalid arguments");
        return;
    } else if (obj->thread() != thread() || thread() != QThread::currentThread()) {
        qWarning("QObject::startTimer: timers cannot be started from another thread");
        return;
    }
#endif

    Q_D(QEventDispatcherEpoll);
    d->timerList.registerTimer(timerId, interval, obj);
}

/*!
    \internal
*/
bool QEventDispatcherEpoll::unregisterTimer(int timerId)
{
#ifndef QT_NO_DEBUG
    if (timerId < 1) {
        qWarning("QEventDispatcherUNIX::unregisterTimer: invalid argument");
        return false;
    } else if (thread() != QThread::currentThread()) {
        qWarning("QObject::killTimer: timers cannot be stopped from another thread");
        return false;
    }
#endif

    Q_D(QEventDispatcherEpoll);
    return d->timerList.unregisterTimer(timerId);
}

/*!
    \internal
*/
bool QEventDispatcherEpoll::unregisterTimers(QObject *object)
{
#ifndef QT_NO_DEBUG
    if (!object) {
        qWarning("QEventDispatcherUNIX::unregisterTimers: invalid argument");
        return false;
    } else if (object->thread() != thread() || thread() != QThread::currentThread()) {
        qWarning("QObject::killTimers: timers cannot be stopped from another thread");
        return false;
    }
#endif

    Q_D(QEventDispatcherEpoll);
    return d->timerList.unregisterTimers(object);
}

QList<QEventDispatcherEpoll::TimerInfo>
QEventDispatcherEpoll::registeredTimers(QObject *object) const
{
    if (!object) {
        qWarning("QEventDispatcherUNIX:registeredTimers: invalid argument");
        return QList<TimerInfo>();
    }

    Q_D(const QEventDispatcherEpoll);
    return d->timerList.registeredTimers(object);
}

/*****************************************************************************
 QEventDispatcher implementations for UNIX
 *****************************************************************************/

static int epoll_event_type_from_socknot_type( int type )
{
    switch(type) {
    case QSocketNotifier::Read: return EPOLLIN;
    case QSocketNotifier::Write: return EPOLLOUT;
    }
    return 0;
}

void QEventDispatcherEpoll::registerSocketNotifier(QSocketNotifier *notifier)
{
    Q_D(QEventDispatcherEpoll);

    //qDebug() << "###registering " << notifier << " fd: " << notifier->socket() << " type:" << notifier->type();

    Q_ASSERT(notifier);
    const int sockfd = notifier->socket();
    const int type = notifier->type();
#ifndef QT_NO_DEBUG
    if (sockfd < 0) {
        qWarning("QSocketNotifier: Internal error");
        return;
    } else if (notifier->thread() != thread()
               || thread() != QThread::currentThread()) {
        qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread");
        return;
    }
#endif

    int newevent = epoll_event_type_from_socknot_type(type);

    QEventDispatcherEpollPrivate::SocketNotifierList::iterator it = d->socketNotifiers.find(sockfd);
    if( it != d->socketNotifiers.end() ) {
        /* We are already monitoring this FD,
         * add it to the list and figure out
         * if we are monitoring the right events
         * already.
         */
        int events = 0;
        Q_FOREACH( QSocketNotifier* sn, *it ) {
            events |= epoll_event_type_from_socknot_type(sn->type());
        }
        (*it).push_back(notifier);

        if( (events | newevent) != events ) {
            /* We are not, so add the new event type to the set */
            epoll_event ep;
            memset(&ep,0,sizeof(ep));
            ep.events = events | newevent;
            ep.data.fd = sockfd;
            int rc = epoll_ctl(d->epollFD, EPOLL_CTL_MOD, sockfd, &ep);
            if (rc != 0) {
                if (errno == ENOENT) {
                    /* Huh, gone? Try adding it */
                    int rc = epoll_ctl(d->epollFD, EPOLL_CTL_ADD, sockfd, &ep);
                    if( rc != 0 ) perror("QEventDispatcherEpoll::registerSocketNotifier(), epoll_ctl ADD failed: ");
                } else
                    perror("QEventDispatcherEpoll::registerSocketNotifier(), epoll_ctl MOD failed: ");
            }
        }
    } else {
        d->socketNotifiers.insert(sockfd,QList<QSocketNotifier*>() << notifier);

        epoll_event ep;
        memset(&ep,0,sizeof(ep));
        ep.events = newevent;
        ep.data.fd = sockfd;

        int rc = epoll_ctl(d->epollFD, EPOLL_CTL_ADD, sockfd, &ep);
        if( rc != 0 ) perror("QEventDispatcherEpoll::registerSocketNotifier(), epoll_ctl ADD failed: ");
    }
}

void QEventDispatcherEpoll::unregisterSocketNotifier(QSocketNotifier *notifier)
{
    Q_D(QEventDispatcherEpoll);

    Q_ASSERT(notifier);
    const int sockfd = notifier->socket();
    //qDebug() << "###unregistering " << notifier << " fd: " << notifier->socket();
#ifndef QT_NO_DEBUG
    if (sockfd < 0) {
        qWarning("QSocketNotifier: Internal error");
        return;
    } else if (notifier->thread() != thread()
               || thread() != QThread::currentThread()) {
        qWarning("QSocketNotifier: socket notifiers cannot be disabled from another thread");
        return;
    }
#endif
    d->sn_pending_list.removeAll(notifier);

    QEventDispatcherEpollPrivate::SocketNotifierList::iterator it = d->socketNotifiers.find(sockfd);
    if( it != d->socketNotifiers.end() ) {
        (*it).removeOne(notifier);
        if( (*it).isEmpty() ) {
            epoll_event dummy;
            memset(&dummy,0,sizeof(dummy));
            int rc = epoll_ctl(d->epollFD, EPOLL_CTL_DEL, sockfd, &dummy);
            if( rc != 0 ) perror("QEventDispatcherEpoll::unregisterSocketNotifier(), epoll_ctl failed: ");
        } else {
            int events = 0;
            Q_FOREACH( QSocketNotifier* sn, *it ) {
                events |= epoll_event_type_from_socknot_type(sn->type());
            }
            epoll_event ep;
            memset(&ep,0,sizeof(ep));
            ep.events = events;
            ep.data.fd = sockfd;
            int rc = epoll_ctl(d->epollFD, EPOLL_CTL_MOD, sockfd, &ep);
            if( rc != 0 ) perror("QEventDispatcherEpoll::registerSocketNotifier(), epoll_ctl MOD failed: ");
        }
    }
}

int QEventDispatcherEpoll::activateTimers()
{
    Q_ASSERT(thread() == QThread::currentThread());
    Q_D(QEventDispatcherEpoll);
    return d->timerList.activateTimers();
}

int QEventDispatcherEpoll::activateSocketNotifiers(int nevents, epoll_event* events)
{
    //qDebug() << "QEventDispatcherEpoll::activateSocketNotifiers(" << nevents << events << ")";
    Q_D(QEventDispatcherEpoll);
    if(nevents <= 0)
        return 0;

    // activate entries
    int n_act = 0;
    QEvent event(QEvent::SockAct);
    for(int i = 0; i < nevents; ++i) {
        if(events[i].data.fd == d->thread_pipe[0] /*|| events[i].data.fd == d->thread_pipe[1]*/) {
            //qDebug() << "thread pipe!";
            //epoll_ctl(d->epollFD, EPOLL_CTL_DEL, events[i].data.fd, &events[i]);
            continue;
        }

        QEventDispatcherEpollPrivate::SocketNotifierList::iterator it = d->socketNotifiers.find(events[i].data.fd);
        if( it != d->socketNotifiers.end() ) {
            d->sn_pending_list = *it;
            while (!d->sn_pending_list.isEmpty()) {
                QSocketNotifier* notifier = d->sn_pending_list.takeLast();
                Q_ASSERT(notifier);

                QCoreApplication::sendEvent(notifier, &event);
            }
        }

        ++n_act;
    }

    return n_act;
}

bool QEventDispatcherEpoll::processEvents(QEventLoop::ProcessEventsFlags flags)
{
    //qDebug("QEventDispatcherEpoll::processEvents");
    Q_D(QEventDispatcherEpoll);
    d->interrupt = false;

    // we are awake, broadcast it
    Q_EMIT awake();
    QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData);

    int nevents = 0;
    const bool canWait = (d->threadData->canWait
                          && !d->interrupt
                          && (flags & QEventLoop::WaitForMoreEvents));

    if (canWait)
        Q_EMIT aboutToBlock();

    if (!d->interrupt) {
        // return the maximum time we can wait for an event.
        timeval *tm = 0;
        timeval wait_tm = { 0l, 0l };
        if (!(flags & QEventLoop::X11ExcludeTimers)) {
            if (d->timerList.timerWait(wait_tm))
                tm = &wait_tm;
        }

        if (!canWait) {
            if (!tm)
                tm = &wait_tm;

            // no time to wait
            tm->tv_sec  = 0l;
            tm->tv_usec = 0l;
        }

        nevents = d->doSelect(flags, tm);

        // activate timers
        if (! (flags & QEventLoop::X11ExcludeTimers)) {
            nevents += activateTimers();
        }
    }
    //qDebug("Returning from processEvents");
    // return true if we handled events, false otherwise
    return (nevents > 0);
}

bool QEventDispatcherEpoll::hasPendingEvents()
{
    extern uint qGlobalPostedEventsCount(); // from qapplication.cpp
    return qGlobalPostedEventsCount();
}

void QEventDispatcherEpoll::wakeUp()
{
    Q_D(QEventDispatcherEpoll);
    if (d->wakeUps.testAndSetAcquire(0, 1)) {
        char c = 0;
        qt_safe_write( d->thread_pipe[1], &c, 1 );
    }
}

void QEventDispatcherEpoll::interrupt()
{
    Q_D(QEventDispatcherEpoll);
    d->interrupt = true;
    wakeUp();
}

void QEventDispatcherEpoll::flush()
{ }

QT_END_NAMESPACE
<commit_msg>Removed select()-specifc stuff and changed QEventDispatcherUNIX to QEventDispatcherEpoll in strings<commit_after>/*****************************************************************************
** Copyright (C) 2011 Connected Table AB
**
** An epoll based event dispatcher for Qt.
**
** Notable work by Steffen Hansen and Tobias Nätterlund of KDAB
******************************************************************************/

#include <qplatformdefs.h>

#include <qcoreapplication.h>
#include <qpair.h>
#include <qsocketnotifier.h>
#include <qthread.h>
#include <qelapsedtimer.h>

#include "qeventdispatcher_epoll.h"
#include <private/qthread_p.h>
#include <private/qcoreapplication_p.h>
#include <private/qcore_unix_p.h>

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/epoll.h>

#include <QDebug>

QT_BEGIN_NAMESPACE

/*****************************************************************************
 UNIX signal handling
 *****************************************************************************/

QEventDispatcherEpollPrivate::QEventDispatcherEpollPrivate()
{
    epollFD = epoll_create(16384);
//    qDebug() << "epollFD =" << epollFD;

    bool pipefail = false;

    // initialize the common parts of the event loop
    if (qt_safe_pipe(thread_pipe, O_NONBLOCK) == -1) {
        perror("QEventDispatcherEpollPrivate(): Unable to create thread pipe");
        pipefail = true;
    }

    if (pipefail)
        qFatal("QEventDispatcherEpollPrivate(): Can not continue without a thread pipe");

    epoll_event ev;
    memset(&ev,0,sizeof(ev));
    ev.data.fd = thread_pipe[0];
    ev.events = EPOLLIN;//| EPOLLOUT | EPOLLPRI;
    int rc = epoll_ctl(epollFD, EPOLL_CTL_ADD, thread_pipe[0], &ev);
    if( rc != 0 ) perror("QEventDispatcherEpollPrivate::doSelect(), epoll_ctl failed: ");

    interrupt = false;
}

QEventDispatcherEpollPrivate::~QEventDispatcherEpollPrivate()
{
    // cleanup the common parts of the event loop
    close(thread_pipe[0]);
    close(thread_pipe[1]);

    close(epollFD);

    // cleanup timers
    qDeleteAll(timerList);
}

#define EVENT_COUNT 100

int QEventDispatcherEpollPrivate::doSelect(QEventLoop::ProcessEventsFlags flags, timeval *timeout)
{
    Q_Q(QEventDispatcherEpoll);

//    qDebug() << "QEventDispatcherEpollPrivate::doSelect(" << flags << timeout << ")";

    // needed in QEventDispatcherUNIX::select()
    timerList.updateCurrentTime();

    int nsel = 0;
    epoll_event events[EVENT_COUNT];
    memset(events,0,sizeof(epoll_event)*EVENT_COUNT);
    int nevents = 0;
    do {
        if(timeout)
            nsel = epoll_wait(epollFD, events, EVENT_COUNT, timeout->tv_sec * 1000 + timeout->tv_usec / 1000);
        else // timeout == NULL means wait indefinitely for select(), -1 does the same for epoll_wait()
            nsel = epoll_wait(epollFD, events, EVENT_COUNT, -1);
        //qDebug() << "nsel after epoll_wait =" << nsel;
    } while (nsel == -1 && (errno == EINTR || errno == EAGAIN));

    if (nsel == -1) {
        // EINVAL... shouldn't happen, so let's complain to stderr
        // and hope someone sends us a bug report
        perror("epoll_wait()");
    }

    // some other thread woke us up... consume the data on the thread pipe so that
    // select doesn't immediately return next time
    for(int i = 0; i < nsel; ++i) {
        if(events[i].data.fd == thread_pipe[0]) {
            //qDebug("Reading thread_pipe[0]");
            char c[16];
            while (::read(thread_pipe[0], c, sizeof(c)) > 0)
                ;
            if (!wakeUps.testAndSetRelease(1, 0)) {
                // hopefully, this is dead code
                qWarning("QEventDispatcherEpoll: internal error, wakeUps.testAndSetRelease(1, 0) failed!");
            }
            ++nevents;
            break;
        }
    }

    // activate socket notifiers
    if(! (flags & QEventLoop::ExcludeSocketNotifiers) && nsel > 0)
        return nevents + q->activateSocketNotifiers(nsel, events);
    else
        return nevents;
}

QEventDispatcherEpoll::QEventDispatcherEpoll(QObject *parent)
    : QAbstractEventDispatcher(*new QEventDispatcherEpollPrivate, parent)
{ }

QEventDispatcherEpoll::QEventDispatcherEpoll(QEventDispatcherEpollPrivate &dd, QObject *parent)
    : QAbstractEventDispatcher(dd, parent)
{ }

QEventDispatcherEpoll::~QEventDispatcherEpoll()
{
    Q_D(QEventDispatcherEpoll);
    d->threadData->eventDispatcher = 0;
}

/*!
    \internal
*/
void QEventDispatcherEpoll::registerTimer(int timerId, int interval, QObject *obj)
{
#ifndef QT_NO_DEBUG
    if (timerId < 1 || interval < 0 || !obj) {
        qWarning("QEventDispatcherEpoll::registerTimer: invalid arguments");
        return;
    } else if (obj->thread() != thread() || thread() != QThread::currentThread()) {
        qWarning("QObject::startTimer: timers cannot be started from another thread");
        return;
    }
#endif

    Q_D(QEventDispatcherEpoll);
    d->timerList.registerTimer(timerId, interval, obj);
}

/*!
    \internal
*/
bool QEventDispatcherEpoll::unregisterTimer(int timerId)
{
#ifndef QT_NO_DEBUG
    if (timerId < 1) {
        qWarning("QEventDispatcherEpoll::unregisterTimer: invalid argument");
        return false;
    } else if (thread() != QThread::currentThread()) {
        qWarning("QObject::killTimer: timers cannot be stopped from another thread");
        return false;
    }
#endif

    Q_D(QEventDispatcherEpoll);
    return d->timerList.unregisterTimer(timerId);
}

/*!
    \internal
*/
bool QEventDispatcherEpoll::unregisterTimers(QObject *object)
{
#ifndef QT_NO_DEBUG
    if (!object) {
        qWarning("QEventDispatcherEpoll::unregisterTimers: invalid argument");
        return false;
    } else if (object->thread() != thread() || thread() != QThread::currentThread()) {
        qWarning("QObject::killTimers: timers cannot be stopped from another thread");
        return false;
    }
#endif

    Q_D(QEventDispatcherEpoll);
    return d->timerList.unregisterTimers(object);
}

QList<QEventDispatcherEpoll::TimerInfo>
QEventDispatcherEpoll::registeredTimers(QObject *object) const
{
    if (!object) {
        qWarning("QEventDispatcherEpoll::registeredTimers: invalid argument");
        return QList<TimerInfo>();
    }

    Q_D(const QEventDispatcherEpoll);
    return d->timerList.registeredTimers(object);
}

/*****************************************************************************
 QEventDispatcher implementations for UNIX
 *****************************************************************************/

static int epoll_event_type_from_socknot_type( int type )
{
    switch(type) {
    case QSocketNotifier::Read: return EPOLLIN;
    case QSocketNotifier::Write: return EPOLLOUT;
    }
    return 0;
}

void QEventDispatcherEpoll::registerSocketNotifier(QSocketNotifier *notifier)
{
    Q_D(QEventDispatcherEpoll);

    //qDebug() << "###registering " << notifier << " fd: " << notifier->socket() << " type:" << notifier->type();

    Q_ASSERT(notifier);
    const int sockfd = notifier->socket();
    const int type = notifier->type();
#ifndef QT_NO_DEBUG
    if (sockfd < 0) {
        qWarning("QSocketNotifier: Internal error");
        return;
    } else if (notifier->thread() != thread()
               || thread() != QThread::currentThread()) {
        qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread");
        return;
    }
#endif

    int newevent = epoll_event_type_from_socknot_type(type);

    QEventDispatcherEpollPrivate::SocketNotifierList::iterator it = d->socketNotifiers.find(sockfd);
    if( it != d->socketNotifiers.end() ) {
        /* We are already monitoring this FD,
         * add it to the list and figure out
         * if we are monitoring the right events
         * already.
         */
        int events = 0;
        Q_FOREACH( QSocketNotifier* sn, *it ) {
            events |= epoll_event_type_from_socknot_type(sn->type());
        }
        (*it).push_back(notifier);

        if( (events | newevent) != events ) {
            /* We are not, so add the new event type to the set */
            epoll_event ep;
            memset(&ep,0,sizeof(ep));
            ep.events = events | newevent;
            ep.data.fd = sockfd;
            int rc = epoll_ctl(d->epollFD, EPOLL_CTL_MOD, sockfd, &ep);
            if (rc != 0) {
                if (errno == ENOENT) {
                    /* Huh, gone? Try adding it */
                    int rc = epoll_ctl(d->epollFD, EPOLL_CTL_ADD, sockfd, &ep);
                    if( rc != 0 ) perror("QEventDispatcherEpoll::registerSocketNotifier(), epoll_ctl ADD failed: ");
                } else
                    perror("QEventDispatcherEpoll::registerSocketNotifier(), epoll_ctl MOD failed: ");
            }
        }
    } else {
        d->socketNotifiers.insert(sockfd,QList<QSocketNotifier*>() << notifier);

        epoll_event ep;
        memset(&ep,0,sizeof(ep));
        ep.events = newevent;
        ep.data.fd = sockfd;

        int rc = epoll_ctl(d->epollFD, EPOLL_CTL_ADD, sockfd, &ep);
        if( rc != 0 ) perror("QEventDispatcherEpoll::registerSocketNotifier(), epoll_ctl ADD failed: ");
    }
}

void QEventDispatcherEpoll::unregisterSocketNotifier(QSocketNotifier *notifier)
{
    Q_D(QEventDispatcherEpoll);

    Q_ASSERT(notifier);
    const int sockfd = notifier->socket();
    //qDebug() << "###unregistering " << notifier << " fd: " << notifier->socket();
#ifndef QT_NO_DEBUG
    if (sockfd < 0) {
        qWarning("QSocketNotifier: Internal error");
        return;
    } else if (notifier->thread() != thread()
               || thread() != QThread::currentThread()) {
        qWarning("QSocketNotifier: socket notifiers cannot be disabled from another thread");
        return;
    }
#endif
    d->sn_pending_list.removeAll(notifier);

    QEventDispatcherEpollPrivate::SocketNotifierList::iterator it = d->socketNotifiers.find(sockfd);
    if( it != d->socketNotifiers.end() ) {
        (*it).removeOne(notifier);
        if( (*it).isEmpty() ) {
            epoll_event dummy;
            memset(&dummy,0,sizeof(dummy));
            int rc = epoll_ctl(d->epollFD, EPOLL_CTL_DEL, sockfd, &dummy);
            if( rc != 0 ) perror("QEventDispatcherEpoll::unregisterSocketNotifier(), epoll_ctl failed: ");
        } else {
            int events = 0;
            Q_FOREACH( QSocketNotifier* sn, *it ) {
                events |= epoll_event_type_from_socknot_type(sn->type());
            }
            epoll_event ep;
            memset(&ep,0,sizeof(ep));
            ep.events = events;
            ep.data.fd = sockfd;
            int rc = epoll_ctl(d->epollFD, EPOLL_CTL_MOD, sockfd, &ep);
            if( rc != 0 ) perror("QEventDispatcherEpoll::registerSocketNotifier(), epoll_ctl MOD failed: ");
        }
    }
}

int QEventDispatcherEpoll::activateTimers()
{
    Q_ASSERT(thread() == QThread::currentThread());
    Q_D(QEventDispatcherEpoll);
    return d->timerList.activateTimers();
}

int QEventDispatcherEpoll::activateSocketNotifiers(int nevents, epoll_event* events)
{
    //qDebug() << "QEventDispatcherEpoll::activateSocketNotifiers(" << nevents << events << ")";
    Q_D(QEventDispatcherEpoll);
    if(nevents <= 0)
        return 0;

    // activate entries
    int n_act = 0;
    QEvent event(QEvent::SockAct);
    for(int i = 0; i < nevents; ++i) {
        if(events[i].data.fd == d->thread_pipe[0] /*|| events[i].data.fd == d->thread_pipe[1]*/) {
            //qDebug() << "thread pipe!";
            //epoll_ctl(d->epollFD, EPOLL_CTL_DEL, events[i].data.fd, &events[i]);
            continue;
        }

        QEventDispatcherEpollPrivate::SocketNotifierList::iterator it = d->socketNotifiers.find(events[i].data.fd);
        if( it != d->socketNotifiers.end() ) {
            d->sn_pending_list = *it;
            while (!d->sn_pending_list.isEmpty()) {
                QSocketNotifier* notifier = d->sn_pending_list.takeLast();
                Q_ASSERT(notifier);

                QCoreApplication::sendEvent(notifier, &event);
            }
        }

        ++n_act;
    }

    return n_act;
}

bool QEventDispatcherEpoll::processEvents(QEventLoop::ProcessEventsFlags flags)
{
    //qDebug("QEventDispatcherEpoll::processEvents");
    Q_D(QEventDispatcherEpoll);
    d->interrupt = false;

    // we are awake, broadcast it
    Q_EMIT awake();
    QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData);

    int nevents = 0;
    const bool canWait = (d->threadData->canWait
                          && !d->interrupt
                          && (flags & QEventLoop::WaitForMoreEvents));

    if (canWait)
        Q_EMIT aboutToBlock();

    if (!d->interrupt) {
        // return the maximum time we can wait for an event.
        timeval *tm = 0;
        timeval wait_tm = { 0l, 0l };
        if (!(flags & QEventLoop::X11ExcludeTimers)) {
            if (d->timerList.timerWait(wait_tm))
                tm = &wait_tm;
        }

        if (!canWait) {
            if (!tm)
                tm = &wait_tm;

            // no time to wait
            tm->tv_sec  = 0l;
            tm->tv_usec = 0l;
        }

        nevents = d->doSelect(flags, tm);

        // activate timers
        if (! (flags & QEventLoop::X11ExcludeTimers)) {
            nevents += activateTimers();
        }
    }
    //qDebug("Returning from processEvents");
    // return true if we handled events, false otherwise
    return (nevents > 0);
}

bool QEventDispatcherEpoll::hasPendingEvents()
{
    extern uint qGlobalPostedEventsCount(); // from qapplication.cpp
    return qGlobalPostedEventsCount();
}

void QEventDispatcherEpoll::wakeUp()
{
    Q_D(QEventDispatcherEpoll);
    if (d->wakeUps.testAndSetAcquire(0, 1)) {
        char c = 0;
        qt_safe_write( d->thread_pipe[1], &c, 1 );
    }
}

void QEventDispatcherEpoll::interrupt()
{
    Q_D(QEventDispatcherEpoll);
    d->interrupt = true;
    wakeUp();
}

void QEventDispatcherEpoll::flush()
{ }

QT_END_NAMESPACE
<|endoftext|>


<commit_before>// __BEGIN_LICENSE__
//
// Copyright (C) 2006 United States Government as represented by the
// Administrator of the National Aeronautics and Space Administration
// (NASA).  All Rights Reserved.
//
// Copyright 2006 Carnegie Mellon University. All rights reserved.
//
// This software is distributed under the NASA Open Source Agreement
// (NOSA), version 1.3.  The NOSA has been approved by the Open Source
// Initiative.  See the file COPYING at the top of the distribution
// directory tree for the complete NOSA document.
//
// THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
// KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
// LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
// SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
// A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
// THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
// DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
//
// __END_LICENSE__
#include <vw/Math/Matrix.h>
#include <vw/Core/Exception.h>
#include <vw/Cartography/DiskImageResourceGeoReferenceHelperGDAL.h>
#include <vw/FileIO/DiskImageResourceGDAL.h>
#include <vw/Cartography/GeoReference.h>

//FIXME: can probably trim down these headers
// GDAL Headers
#include "gdal.h"
#include "gdal_priv.h"
#include "cpl_string.h"
#include "ogr_spatialref.h"
#include "ogr_api.h"

// For boost::split
#include <boost/algorithm/string.hpp>

namespace vw {
namespace cartography {

  /*static*/ void DiskImageResourceGeoReferenceHelperGDAL::read_georeference( FileMetadata* georef_, DiskImageResource* r_ ) {
    DiskImageResourceGDAL* r = (DiskImageResourceGDAL*)r_;
    GeoReference* georef = (GeoReference*)georef_;
    GDALDataset* dataset = (GDALDataset*)(r->dataset());

    if (!dataset)
      vw_throw( LogicErr() << "DiskImageResourceGeoReferenceHelperGDAL: Could not read georeference. No file has been opened." );

    // Pull the projection and datum information out of the file if available
    if( dataset->GetProjectionRef() != NULL ) {

      // Create a GDAL spatial ref object
      OGRSpatialReference gdal_spatial_ref;
      const char* wkt = dataset->GetProjectionRef();
      char** wkt_ptr = (char**)(&wkt);
      gdal_spatial_ref.importFromWkt(wkt_ptr);

      // Read projection information out of the file
      char* proj_str_tmp;
      gdal_spatial_ref.exportToProj4(&proj_str_tmp);
      std::string proj4_str = proj_str_tmp;
      delete proj_str_tmp;
      // For debugging:
      //      vw_out(0) << "PROJ in --> " << proj4_str << "\n";

      std::vector<std::string> input_strings;
      std::vector<std::string> output_strings;
      std::string trimmed_proj4_str = boost::trim_copy(proj4_str);
      boost::split( input_strings, trimmed_proj4_str, boost::is_any_of(" ") );
      for (unsigned int i = 0; i < input_strings.size(); ++i) {

        // Pick out the parts of the projection string that pertain to
        // map projections.  We essentially want to eliminate all of
        // the strings that have to do with the datum, since those are
        // handled by interacting directly with the
        // OGRSpatialReference below. This is sort of messy, but it's
        // the easiest way to do this, as far as I can tell.
        if ((input_strings[i].find("+proj=") == 0) ||
            (input_strings[i].find("+x_0=") == 0) ||
            (input_strings[i].find("+y_0=") == 0) ||
            (input_strings[i].find("+lon") == 0) ||
            (input_strings[i].find("+lat") == 0) ||
            (input_strings[i].find("+k=") == 0) ||
            (input_strings[i].find("+lat_ts=") == 0) ||
            (input_strings[i].find("+ns") == 0) ||
            (input_strings[i].find("+no_cut") == 0) ||
            (input_strings[i].find("+h=") == 0) ||
            (input_strings[i].find("+W=") == 0) ||
            (input_strings[i].find("+units=") == 0)) {
          output_strings.push_back(input_strings[i]);
        }
      }
      std::ostringstream strm;
      for (unsigned int i = 0; i < output_strings.size(); ++i) {
        strm << output_strings[i] << " ";
      }
      // For debugging:
      //      vw_out(0) << "     out --> " << strm.str() << "\n";

      // If the file contains no projection related information, we
      // supply proj.4 with a "default" interpretation that the file
      // is in geographic (unprojected) coordinates.
      if (output_strings.size() == 0)
        georef->set_proj4_projection_str("+proj=longlat");
      else
        georef->set_proj4_projection_str(strm.str());

      // Read in the datum information
      Datum datum;
      const char* datum_name = gdal_spatial_ref.GetAttrValue("DATUM");
      if (datum_name) { datum.name() = datum_name; }
      const char* spheroid_name = gdal_spatial_ref.GetAttrValue("SPHEROID");
      if (spheroid_name) { datum.spheroid_name() = spheroid_name; }
      const char* meridian_name = gdal_spatial_ref.GetAttrValue("PRIMEM");
      if (meridian_name) { datum.meridian_name() = meridian_name; }
      OGRErr e1, e2;
      double semi_major = gdal_spatial_ref.GetSemiMajor(&e1);
      double semi_minor = gdal_spatial_ref.GetSemiMinor(&e2);
      if (e1 != OGRERR_FAILURE && e2 != OGRERR_FAILURE) {
        datum.set_semi_major_axis(semi_major);
        datum.set_semi_minor_axis(semi_minor);
      }
      datum.meridian_offset() = gdal_spatial_ref.GetPrimeMeridian();
      georef->set_datum(datum);
    }

    double geo_transform[6];
    Matrix<double,3,3> transform;
    if( dataset->GetGeoTransform( geo_transform ) == CE_None ) {
      transform.set_identity();
      transform(0,0) = geo_transform[1];
      transform(0,1) = geo_transform[2];
      transform(0,2) = geo_transform[0];
      transform(1,0) = geo_transform[4];
      transform(1,1) = geo_transform[5];
      transform(1,2) = geo_transform[3];
      georef->set_transform(transform);

      // Determine the pixel interpretation for the image.  See the
      // comments in GeoReference for more information.  If nothing is
      // encoded in the file, the default is to assume PixelAsArea.
      georef->set_pixel_interpretation(GeoReference::PixelAsArea);
      char **metadata = dataset->GetMetadata();
      if( CSLCount(metadata) > 0 ) {
        for( int i = 0; metadata[i] != NULL; i++ ) {
          std::vector<std::string> split_vec;
          boost::split(split_vec, metadata[i], boost::is_any_of("=") );
          if (split_vec[0] == GDALMD_AREA_OR_POINT && split_vec.size() >= 2)
            if (boost::trim_copy(split_vec[1]) == GDALMD_AOP_POINT)
              georef->set_pixel_interpretation(GeoReference::PixelAsPoint);
        }
      }

    }
  }

  /*static*/ void DiskImageResourceGeoReferenceHelperGDAL::write_georeference( DiskImageResource* r_, FileMetadata const* georef_ ) {
    DiskImageResourceGDAL* r = (DiskImageResourceGDAL*)r_;
    GeoReference const* georef = (GeoReference const*)georef_;
    GDALDataset* dataset = (GDALDataset*)(r->dataset());

    if (!dataset)
      vw_throw( LogicErr() << "DiskImageResourceGeoReferenceHelperGDAL: Could not write georeference. No file has been opened." );

    // Store the transform matrix
    double geo_transform[6] = { georef->transform()(0,2), georef->transform()(0,0), georef->transform()(0,1),
                                georef->transform()(1,2), georef->transform()(1,0), georef->transform()(1,1) };
    dataset->SetGeoTransform( geo_transform );

    // This is a little ridiculous, but GDAL can't write geotiffs
    // without a string of Well Known Text (WKT), so we must conjure
    // up an OGRSpatialReference here and use it to convert from
    // proj.4 to WKT.
    OGRSpatialReference gdal_spatial_ref;
    gdal_spatial_ref.importFromProj4(georef->proj4_str().c_str());
    char* wkt_str_tmp;
    gdal_spatial_ref.exportToWkt(&wkt_str_tmp);
    std::string wkt_str = wkt_str_tmp;
    delete wkt_str_tmp;

    dataset->SetProjection( wkt_str.c_str() );

    // Set the pixel interpretation for the image.  See the comments
    // in GeoReference for more information.
    if (georef->pixel_interpretation() == GeoReference::PixelAsArea)
      dataset->SetMetadataItem(GDALMD_AREA_OR_POINT, GDALMD_AOP_AREA);
    else // PixelAsPoint
      dataset->SetMetadataItem(GDALMD_AREA_OR_POINT, GDALMD_AOP_POINT);
  }

}} // namespace vw::cartography
<commit_msg>Fixed a bug in writing GDAL files.  We weren't saving any datum information and this sometimes would lead to a missing GCS tag in geotiffs.<commit_after>// __BEGIN_LICENSE__
//
// Copyright (C) 2006 United States Government as represented by the
// Administrator of the National Aeronautics and Space Administration
// (NASA).  All Rights Reserved.
//
// Copyright 2006 Carnegie Mellon University. All rights reserved.
//
// This software is distributed under the NASA Open Source Agreement
// (NOSA), version 1.3.  The NOSA has been approved by the Open Source
// Initiative.  See the file COPYING at the top of the distribution
// directory tree for the complete NOSA document.
//
// THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
// KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
// LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
// SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
// A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
// THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
// DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
//
// __END_LICENSE__
#include <vw/Math/Matrix.h>
#include <vw/Core/Exception.h>
#include <vw/Cartography/DiskImageResourceGeoReferenceHelperGDAL.h>
#include <vw/FileIO/DiskImageResourceGDAL.h>
#include <vw/Cartography/GeoReference.h>

//FIXME: can probably trim down these headers
// GDAL Headers
#include "gdal.h"
#include "gdal_priv.h"
#include "cpl_string.h"
#include "ogr_spatialref.h"
#include "ogr_api.h"

// For boost::split
#include <boost/algorithm/string.hpp>

namespace vw {
namespace cartography {

  /*static*/ void DiskImageResourceGeoReferenceHelperGDAL::read_georeference( FileMetadata* georef_, DiskImageResource* r_ ) {
    DiskImageResourceGDAL* r = (DiskImageResourceGDAL*)r_;
    GeoReference* georef = (GeoReference*)georef_;
    GDALDataset* dataset = (GDALDataset*)(r->dataset());

    if (!dataset)
      vw_throw( LogicErr() << "DiskImageResourceGeoReferenceHelperGDAL: Could not read georeference. No file has been opened." );

    // Pull the projection and datum information out of the file if available
    if( dataset->GetProjectionRef() != NULL ) {

      // Create a GDAL spatial ref object
      OGRSpatialReference gdal_spatial_ref;
      const char* wkt = dataset->GetProjectionRef();
      char** wkt_ptr = (char**)(&wkt);
      gdal_spatial_ref.importFromWkt(wkt_ptr);

      // Read projection information out of the file
      char* proj_str_tmp;
      gdal_spatial_ref.exportToProj4(&proj_str_tmp);
      std::string proj4_str = proj_str_tmp;
      delete proj_str_tmp;
      // For debugging:
      //      vw_out(0) << "PROJ in --> " << proj4_str << "\n";

      std::vector<std::string> input_strings;
      std::vector<std::string> output_strings;
      std::string trimmed_proj4_str = boost::trim_copy(proj4_str);
      boost::split( input_strings, trimmed_proj4_str, boost::is_any_of(" ") );
      for (unsigned int i = 0; i < input_strings.size(); ++i) {

        // Pick out the parts of the projection string that pertain to
        // map projections.  We essentially want to eliminate all of
        // the strings that have to do with the datum, since those are
        // handled by interacting directly with the
        // OGRSpatialReference below. This is sort of messy, but it's
        // the easiest way to do this, as far as I can tell.
        if ((input_strings[i].find("+proj=") == 0) ||
            (input_strings[i].find("+x_0=") == 0) ||
            (input_strings[i].find("+y_0=") == 0) ||
            (input_strings[i].find("+lon") == 0) ||
            (input_strings[i].find("+lat") == 0) ||
            (input_strings[i].find("+k=") == 0) ||
            (input_strings[i].find("+lat_ts=") == 0) ||
            (input_strings[i].find("+ns") == 0) ||
            (input_strings[i].find("+no_cut") == 0) ||
            (input_strings[i].find("+h=") == 0) ||
            (input_strings[i].find("+W=") == 0) ||
            (input_strings[i].find("+units=") == 0)) {
          output_strings.push_back(input_strings[i]);
        }
      }
      std::ostringstream strm;
      for (unsigned int i = 0; i < output_strings.size(); ++i) {
        strm << output_strings[i] << " ";
      }
      // For debugging:
      //      vw_out(0) << "     out --> " << strm.str() << "\n";

      // If the file contains no projection related information, we
      // supply proj.4 with a "default" interpretation that the file
      // is in geographic (unprojected) coordinates.
      if (output_strings.size() == 0)
        georef->set_proj4_projection_str("+proj=longlat");
      else
        georef->set_proj4_projection_str(strm.str());

      // Read in the datum information
      Datum datum;
      const char* datum_name = gdal_spatial_ref.GetAttrValue("DATUM");
      if (datum_name) { datum.name() = datum_name; }
      const char* spheroid_name = gdal_spatial_ref.GetAttrValue("SPHEROID");
      if (spheroid_name) { datum.spheroid_name() = spheroid_name; }
      const char* meridian_name = gdal_spatial_ref.GetAttrValue("PRIMEM");
      if (meridian_name) { datum.meridian_name() = meridian_name; }
      OGRErr e1, e2;
      double semi_major = gdal_spatial_ref.GetSemiMajor(&e1);
      double semi_minor = gdal_spatial_ref.GetSemiMinor(&e2);
      if (e1 != OGRERR_FAILURE && e2 != OGRERR_FAILURE) {
        datum.set_semi_major_axis(semi_major);
        datum.set_semi_minor_axis(semi_minor);
      }
      datum.meridian_offset() = gdal_spatial_ref.GetPrimeMeridian();
      georef->set_datum(datum);
    }

    double geo_transform[6];
    Matrix<double,3,3> transform;
    if( dataset->GetGeoTransform( geo_transform ) == CE_None ) {
      transform.set_identity();
      transform(0,0) = geo_transform[1];
      transform(0,1) = geo_transform[2];
      transform(0,2) = geo_transform[0];
      transform(1,0) = geo_transform[4];
      transform(1,1) = geo_transform[5];
      transform(1,2) = geo_transform[3];
      georef->set_transform(transform);

      // Determine the pixel interpretation for the image.  See the
      // comments in GeoReference for more information.  If nothing is
      // encoded in the file, the default is to assume PixelAsArea.
      georef->set_pixel_interpretation(GeoReference::PixelAsArea);
      char **metadata = dataset->GetMetadata();
      if( CSLCount(metadata) > 0 ) {
        for( int i = 0; metadata[i] != NULL; i++ ) {
          std::vector<std::string> split_vec;
          boost::split(split_vec, metadata[i], boost::is_any_of("=") );
          if (split_vec[0] == GDALMD_AREA_OR_POINT && split_vec.size() >= 2)
            if (boost::trim_copy(split_vec[1]) == GDALMD_AOP_POINT)
              georef->set_pixel_interpretation(GeoReference::PixelAsPoint);
        }
      }

    }
  }

  /*static*/ void DiskImageResourceGeoReferenceHelperGDAL::write_georeference( DiskImageResource* r_, FileMetadata const* georef_ ) {
    DiskImageResourceGDAL* r = (DiskImageResourceGDAL*)r_;
    GeoReference const* georef = (GeoReference const*)georef_;
    GDALDataset* dataset = (GDALDataset*)(r->dataset());

    if (!dataset)
      vw_throw( LogicErr() << "DiskImageResourceGeoReferenceHelperGDAL: Could not write georeference. No file has been opened." );

    // Store the transform matrix
    double geo_transform[6] = { georef->transform()(0,2), georef->transform()(0,0), georef->transform()(0,1),
                                georef->transform()(1,2), georef->transform()(1,0), georef->transform()(1,1) };
    dataset->SetGeoTransform( geo_transform );

    // This is a little ridiculous, but GDAL can't write geotiffs
    // without a string of Well Known Text (WKT), so we must conjure
    // up an OGRSpatialReference here and use it to convert from
    // proj.4 to WKT.
    //
    // However, we first set the datum parameters in the
    // ORGSpatialReference object directly.
    OGRSpatialReference gdal_spatial_ref;
//     gdal_spatial_ref.SetGeogCS( "Geographic Coordinate System",
//                                 georef->datum().name().c_str(),
//                                 georef->datum().spheroid_name().c_str(),
//                                 georef->datum().semi_major_axis(),
//                                 georef->datum().inverse_flattening(),
//                                 georef->datum().meridian_name().c_str(),
//                                 georef->datum().meridian_offset() );
    gdal_spatial_ref.importFromProj4(georef->proj4_str().c_str());
    vw_out(0) << "Creating GeoCS!\n";
    gdal_spatial_ref.SetGeogCS( "Geographic Coordinate System",
                                georef->datum().name().c_str(),
                                georef->datum().spheroid_name().c_str(),
                                georef->datum().semi_major_axis(),
                                georef->datum().inverse_flattening(),
                                georef->datum().meridian_name().c_str(),
                                georef->datum().meridian_offset() );

    char* wkt_str_tmp;
    gdal_spatial_ref.exportToWkt(&wkt_str_tmp);
    std::string wkt_str = wkt_str_tmp;
    delete wkt_str_tmp;

    dataset->SetProjection( wkt_str.c_str() );

    // Set the pixel interpretation for the image.  See the comments
    // in GeoReference for more information.
    if (georef->pixel_interpretation() == GeoReference::PixelAsArea)
      dataset->SetMetadataItem(GDALMD_AREA_OR_POINT, GDALMD_AOP_AREA);
    else // PixelAsPoint
      dataset->SetMetadataItem(GDALMD_AREA_OR_POINT, GDALMD_AOP_POINT);
  }

}} // namespace vw::cartography
<|endoftext|>