<commit_before>#include <iodata/validator>
#include <iodata/storage>

#include <string>
#include <sstream>
#include <set>
#include <map>
using namespace std ;

#include "olson.h"
#include "misc.h"

#include "tzdata.h"

#if DEADCODE
struct tz_single_t ;
struct tz_distinct_t ;

struct tz_distinct_t
{
  olson * guess_timezone(int mcc, tz_suggestions_t &list) ;
  tz_distinct_t(const iodata::record *) ;
  map<int, vector<olson*> > mcc_to_tzlist ;
} ;

struct tz_single_t
{
  olson * guess_timezone(int mcc) ;
  tz_single_t(const iodata::record *) ;
  map<int, string> mcc_to_tz ;
} ;

string mcc_to_xy(int mcc) ; // maps mcc to country code (2 chars)
map<string, vector<string> > xy_to_tz ; // time zones by country code
iodata::validator *validator() ;
iodata::record *open_database(const char *path, const char *type) ;
void read_timezones_by_country() ;

#endif

// we need some some data structures...

// 1. Mapping mcc to alpha-2 code: 310=>US
map<string,string> mcc_to_xy ;
// 2. Mapping alpha-2 to zone to importance (0,1,2,3): US=>(New_York=>0, Chicago=>1, Phoenix=>2, Zaporozhye=>3)
map<string,map<string,int> > xy_to_zone_to_level ;
// 3. Mapping alpha-2 to main zone: US=>New_York
map<string,string> xy_to_zone0 ;
// 4. Default country (alpha-2) and zone based on default time zome customization
string home_country ;
olson *home_zone=NULL ;
// 5. Set of alpha-2 of single zone counties (only 0,1,2 count; 3 doesn't)
set<string> small_countries ;

string tzdata::iso_3166_1_alpha2_by_mcc(const string &mcc)
{
  map<string,string>::const_iterator it = mcc_to_xy.find(mcc) ;
  return it==mcc_to_xy.end() ? "" : it->second ;
}

int tzdata::by_country(const string &alpha2, enum tzdata::zone_type type, set<olson*> &out)
{
  map<string,map<string,int> >::const_iterator it = xy_to_zone_to_level.find(alpha2) ;
  if (it==xy_to_zone_to_level.end())
    return 0 ;

  int counter = 0 ;
  int threshold = type==tzdata::Main_Zones ? 1 : type==tzdata::Real_Zones ? 2 : 3 ; // all by default
  const map<string,int> &zone_to_level = it->second ;

  for (map<string,int>::const_iterator jt=zone_to_level.begin(); jt!=zone_to_level.end(); ++jt)
    if (jt->second <= threshold)
      out.insert(olson::by_name(jt->first)), ++counter ;

  return counter ;
}

olson *tzdata::country_default(const string &alpha2)
{
  map<string,string>::const_iterator it = xy_to_zone0.find(alpha2) ;
  return it==xy_to_zone0.end() ? NULL : olson::by_name(it->second) ;
}

olson *tzdata::device_default()
{
  return home_zone ;
}

int tzdata::filter(const set<olson*> &in, time_t moment, int offset, int dst, set<olson*> &out)
{
  int counter = 0 ;
  for (set<olson*>::const_iterator it=in.begin(); it!=in.end(); ++it)
    if ((*it)->match(moment, offset, dst))
      ++counter, out.insert(*it) ;
  return counter ;
}

bool tzdata::is_single_zone_country(const string &alpha2)
{
  return small_countries.find(alpha2) != small_countries.end() ;
}

string tzdata::set_str(const set<olson*> &x)
{
  ostringstream os ;
  bool first ;
  for (set<olson*>::const_iterator it=x.begin(); it!=x.end(); ++it)
    os << (first ? first=false, "{" : ", " ) << (*it)->name() ;
  os << (first ? " }" : "}") ;
  return os.str() ;
}

// --- initialization ---

static iodata::validator *tzdata_validator = iodata::validator::from_file("/usr/share/timed/typeinfo/tzdata.type") ;

#if 0
static struct tz_distinct_t
{
  // olson * guess_timezone(int mcc, tz_suggestions_t &list) ;
  tz_distinct_t(const iodata::record *) ;
  map<int, vector<olson*> > mcc_to_tzlist ;
}
*tz_distinct=NULL ;

static struct tz_single_t
{
  // olson * guess_timezone(int mcc) ;
  tz_single_t(const iodata::record *) ;
  map<int, string> mcc_to_tz ;
}
tz_single_t *tz_single=NULL ;
#endif

static iodata::record *open_database(const char *path, const char *type)
{
  log_notice("opening file '%s', reading record of type '%s'", path, type) ;
  iodata::storage file ;
  file.set_validator(tzdata_validator, type) ;
  file.set_primary_path(path) ;
  if (iodata::record *res = file.load())
    return res ;
  log_abort("file '%s' corrupted or not present", path) ;
  // return NULL ; TODO: just print an error in init() and continue
}

static void process_zone(const string &xy, const string &tz, int i_value)
{
  if (i_value==0)
    xy_to_zone0[xy] = tz ; // capital
  if (tz==home_zone->name())
    home_country = xy ;
  xy_to_zone_to_level[xy][tz] = i_value ;
}

void tzdata::init(const string &default_tz)
{
  home_zone = olson::by_name(default_tz) ;

  iodata::record *A = open_database("/usr/share/tzdata-timed/country-by-mcc.data", "mcc_to_xy_t") ;
  iodata::record *B = open_database("/usr/share/tzdata-timed/single.data", "tz_single_t") ;
  iodata::record *C = open_database("/usr/share/tzdata-timed/zones-by-country.data", "zones_by_country_t") ;

  const iodata::array *a = A->get("mcc_to_xy")->arr() ;
  for(unsigned i=0; i<a->size(); ++i)
  {
    int mcc_d = a->get(i)->get("mcc")->value() ;
    string mcc = str_printf("%d", mcc_d) ;
    string xy = a->get(i)->get("country")->str() ;
    mcc_to_xy[mcc] = xy ;
  }

  const iodata::array *b = B->get("list")->arr() ; // TODO: rename list->tz_single (here and in tzdata script)
  for(unsigned i=0; i<b->size(); ++i)
  {
    int mcc_d = b->get(i)->get("mcc")->value() ;
    string mcc = str_printf("%d", mcc_d) ;
    string xy = tzdata::iso_3166_1_alpha2_by_mcc(mcc) ;
    if (xy.empty())
    {
      log_critical("Iso-3166 alpha-2 ID not found for MCC=%d", mcc_d) ;
      continue ;
    }
    small_countries.insert(xy) ;
    string tz = b->get(i)->get("tz")->str() ;
    process_zone(xy, tz, 0) ; // 0 is 'capital'
  }

  const iodata::array *c = C->get("xy_to_tz")->arr() ;
  for(unsigned i=0; i<c->size(); ++i)
  {
    // log_debug("i=%d", i) ;
    string xy = c->get(i)->get("xy")->str() ;
    for (int important=1; important<=2; ++important)
    {
      // log_debug("i=%d important=%d", i, important) ;
      const char *key = important==1 ? "major" : "minor" ;
      const iodata::array *list = c->get(i)->get(key)->arr() ;
      for (unsigned j=0; j<list->size(); ++j)
      {
        // log_debug("i=%d important=%d j=%d", i, important, j) ;
        int i_value = (important==1 and j==0) ? 0 : important ; // the very first is the capital
        process_zone(xy, list->get(j)->str(), i_value) ;
      }
    }
  }

  delete A ;
  delete B ;
  delete C ;
}
<commit_msg>a header<commit_after>#include <iodata/validator>
#include <iodata/storage>

#include <string>
#include <sstream>
#include <set>
#include <map>
using namespace std ;

#include <qmlog>

#include "olson.h"
#include "misc.h"

#include "tzdata.h"

#if DEADCODE
struct tz_single_t ;
struct tz_distinct_t ;

struct tz_distinct_t
{
  olson * guess_timezone(int mcc, tz_suggestions_t &list) ;
  tz_distinct_t(const iodata::record *) ;
  map<int, vector<olson*> > mcc_to_tzlist ;
} ;

struct tz_single_t
{
  olson * guess_timezone(int mcc) ;
  tz_single_t(const iodata::record *) ;
  map<int, string> mcc_to_tz ;
} ;

string mcc_to_xy(int mcc) ; // maps mcc to country code (2 chars)
map<string, vector<string> > xy_to_tz ; // time zones by country code
iodata::validator *validator() ;
iodata::record *open_database(const char *path, const char *type) ;
void read_timezones_by_country() ;

#endif

// we need some some data structures...

// 1. Mapping mcc to alpha-2 code: 310=>US
map<string,string> mcc_to_xy ;
// 2. Mapping alpha-2 to zone to importance (0,1,2,3): US=>(New_York=>0, Chicago=>1, Phoenix=>2, Zaporozhye=>3)
map<string,map<string,int> > xy_to_zone_to_level ;
// 3. Mapping alpha-2 to main zone: US=>New_York
map<string,string> xy_to_zone0 ;
// 4. Default country (alpha-2) and zone based on default time zome customization
string home_country ;
olson *home_zone=NULL ;
// 5. Set of alpha-2 of single zone counties (only 0,1,2 count; 3 doesn't)
set<string> small_countries ;

string tzdata::iso_3166_1_alpha2_by_mcc(const string &mcc)
{
  map<string,string>::const_iterator it = mcc_to_xy.find(mcc) ;
  return it==mcc_to_xy.end() ? "" : it->second ;
}

int tzdata::by_country(const string &alpha2, enum tzdata::zone_type type, set<olson*> &out)
{
  map<string,map<string,int> >::const_iterator it = xy_to_zone_to_level.find(alpha2) ;
  if (it==xy_to_zone_to_level.end())
    return 0 ;

  int counter = 0 ;
  int threshold = type==tzdata::Main_Zones ? 1 : type==tzdata::Real_Zones ? 2 : 3 ; // all by default
  const map<string,int> &zone_to_level = it->second ;

  for (map<string,int>::const_iterator jt=zone_to_level.begin(); jt!=zone_to_level.end(); ++jt)
    if (jt->second <= threshold)
      out.insert(olson::by_name(jt->first)), ++counter ;

  return counter ;
}

olson *tzdata::country_default(const string &alpha2)
{
  map<string,string>::const_iterator it = xy_to_zone0.find(alpha2) ;
  return it==xy_to_zone0.end() ? NULL : olson::by_name(it->second) ;
}

olson *tzdata::device_default()
{
  return home_zone ;
}

int tzdata::filter(const set<olson*> &in, time_t moment, int offset, int dst, set<olson*> &out)
{
  int counter = 0 ;
  for (set<olson*>::const_iterator it=in.begin(); it!=in.end(); ++it)
    if ((*it)->match(moment, offset, dst))
      ++counter, out.insert(*it) ;
  return counter ;
}

bool tzdata::is_single_zone_country(const string &alpha2)
{
  return small_countries.find(alpha2) != small_countries.end() ;
}

string tzdata::set_str(const set<olson*> &x)
{
  ostringstream os ;
  bool first ;
  for (set<olson*>::const_iterator it=x.begin(); it!=x.end(); ++it)
    os << (first ? first=false, "{" : ", " ) << (*it)->name() ;
  os << (first ? " }" : "}") ;
  return os.str() ;
}

// --- initialization ---

static iodata::validator *tzdata_validator = iodata::validator::from_file("/usr/share/timed/typeinfo/tzdata.type") ;

#if 0
static struct tz_distinct_t
{
  // olson * guess_timezone(int mcc, tz_suggestions_t &list) ;
  tz_distinct_t(const iodata::record *) ;
  map<int, vector<olson*> > mcc_to_tzlist ;
}
*tz_distinct=NULL ;

static struct tz_single_t
{
  // olson * guess_timezone(int mcc) ;
  tz_single_t(const iodata::record *) ;
  map<int, string> mcc_to_tz ;
}
tz_single_t *tz_single=NULL ;
#endif

static iodata::record *open_database(const char *path, const char *type)
{
  log_notice("opening file '%s', reading record of type '%s'", path, type) ;
  iodata::storage file ;
  file.set_validator(tzdata_validator, type) ;
  file.set_primary_path(path) ;
  if (iodata::record *res = file.load())
    return res ;
  log_abort("file '%s' corrupted or not present", path) ;
  // return NULL ; TODO: just print an error in init() and continue
}

static void process_zone(const string &xy, const string &tz, int i_value)
{
  if (i_value==0)
    xy_to_zone0[xy] = tz ; // capital
  if (tz==home_zone->name())
    home_country = xy ;
  xy_to_zone_to_level[xy][tz] = i_value ;
}

void tzdata::init(const string &default_tz)
{
  home_zone = olson::by_name(default_tz) ;

  iodata::record *A = open_database("/usr/share/tzdata-timed/country-by-mcc.data", "mcc_to_xy_t") ;
  iodata::record *B = open_database("/usr/share/tzdata-timed/single.data", "tz_single_t") ;
  iodata::record *C = open_database("/usr/share/tzdata-timed/zones-by-country.data", "zones_by_country_t") ;

  const iodata::array *a = A->get("mcc_to_xy")->arr() ;
  for(unsigned i=0; i<a->size(); ++i)
  {
    int mcc_d = a->get(i)->get("mcc")->value() ;
    string mcc = str_printf("%d", mcc_d) ;
    string xy = a->get(i)->get("country")->str() ;
    mcc_to_xy[mcc] = xy ;
  }

  const iodata::array *b = B->get("list")->arr() ; // TODO: rename list->tz_single (here and in tzdata script)
  for(unsigned i=0; i<b->size(); ++i)
  {
    int mcc_d = b->get(i)->get("mcc")->value() ;
    string mcc = str_printf("%d", mcc_d) ;
    string xy = tzdata::iso_3166_1_alpha2_by_mcc(mcc) ;
    if (xy.empty())
    {
      log_critical("Iso-3166 alpha-2 ID not found for MCC=%d", mcc_d) ;
      continue ;
    }
    small_countries.insert(xy) ;
    string tz = b->get(i)->get("tz")->str() ;
    process_zone(xy, tz, 0) ; // 0 is 'capital'
  }

  const iodata::array *c = C->get("xy_to_tz")->arr() ;
  for(unsigned i=0; i<c->size(); ++i)
  {
    // log_debug("i=%d", i) ;
    string xy = c->get(i)->get("xy")->str() ;
    for (int important=1; important<=2; ++important)
    {
      // log_debug("i=%d important=%d", i, important) ;
      const char *key = important==1 ? "major" : "minor" ;
      const iodata::array *list = c->get(i)->get(key)->arr() ;
      for (unsigned j=0; j<list->size(); ++j)
      {
        // log_debug("i=%d important=%d j=%d", i, important, j) ;
        int i_value = (important==1 and j==0) ? 0 : important ; // the very first is the capital
        process_zone(xy, list->get(j)->str(), i_value) ;
      }
    }
  }

  delete A ;
  delete B ;
  delete C ;
}
<|endoftext|>


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

void run_part_one() {
}
void run_part_two() {
}

int main(int argc, char* argv[]) {
    if (argc > 1) {
        if (std::string(argv[1]) == "--part_two") {
            run_part_two();
        } else {
            std::cout << "Usage: day21 [--part_two]" << std::endl;
            return -1;
        }
    } else {
        run_part_one();
    }
}
<commit_msg>added runtime code for day 21 part one<commit_after>#include <iostream>
#include <string>

#include "BossFight.hpp"

void run_part_one() {
    std::cout << find_lowest_gold_to_win(100,8,2) << std::endl;
}
void run_part_two() {
}

int main(int argc, char* argv[]) {
    if (argc > 1) {
        if (std::string(argv[1]) == "--part_two") {
            run_part_two();
        } else {
            std::cout << "Usage: day21 [--part_two]" << std::endl;
            return -1;
        }
    } else {
        run_part_one();
    }
}
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Axel Naumann <axel@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "cling/MetaProcessor/MetaProcessor.h"

#include "Display.h"
#include "InputValidator.h"
#include "MetaParser.h"
#include "MetaSema.h"
#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/Value.h"

#include "clang/Basic/FileManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"

#include "llvm/Support/Path.h"

#include <fstream>
#include <cstdlib>
#include <cctype>
#include <stdio.h>
#ifndef WIN32
#include <unistd.h>
#else
#include <io.h>
#define STDIN_FILENO  0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
#endif

using namespace clang;

namespace cling {

  MetaProcessor::MaybeRedirectOutputRAII::MaybeRedirectOutputRAII(
                                          MetaProcessor* p)
  :m_MetaProcessor(p), m_isCurrentlyRedirecting(0) {
    StringRef redirectionFile;
    m_MetaProcessor->increaseRedirectionRAIILevel();
    if (!m_MetaProcessor->m_PrevStdoutFileName.empty()) {
      redirectionFile = m_MetaProcessor->m_PrevStdoutFileName.back();
      redirect(stdout, redirectionFile.str(), kSTDOUT);
    }
    if (!m_MetaProcessor->m_PrevStderrFileName.empty()) {
      redirectionFile = m_MetaProcessor->m_PrevStderrFileName.back();
      // Deal with the case 2>&1 and 2&>1
      if (strcmp(redirectionFile.data(), "_IO_2_1_stdout_") == 0) {
        // If out is redirected to a file.
        if (!m_MetaProcessor->m_PrevStdoutFileName.empty()) {
          redirectionFile = m_MetaProcessor->m_PrevStdoutFileName.back();
        } else {
          unredirect(m_MetaProcessor->m_backupFDStderr, STDERR_FILENO, stderr);
        }
      }
      redirect(stderr, redirectionFile.str(), kSTDERR);
    }
  }

  MetaProcessor::MaybeRedirectOutputRAII::~MaybeRedirectOutputRAII() {
    pop();
    m_MetaProcessor->decreaseRedirectionRAIILevel();
  }

  void MetaProcessor::MaybeRedirectOutputRAII::redirect(FILE* file,
                                        const std::string& fileName,
                                        MetaProcessor::RedirectionScope scope) {
    if (!fileName.empty()) {
      FILE* redirectionFile = freopen(fileName.c_str(), "a", file);
      if (!redirectionFile) {
        llvm::errs()<<"cling::MetaProcessor::MaybeRedirectOutputRAII::redirect:"
                    " Not succefully reopened the redirection file "
                    << fileName.c_str() << "\n.";
      } else {
        m_isCurrentlyRedirecting |= scope;
      }
    }
  }

  void MetaProcessor::MaybeRedirectOutputRAII::pop() {
    //If we have only one redirection RAII
    //only then do the unredirection.
    if (m_MetaProcessor->getRedirectionRAIILevel() != 1)
      return;

    if (m_isCurrentlyRedirecting & kSTDOUT) {
      unredirect(m_MetaProcessor->m_backupFDStdout, STDOUT_FILENO, stdout);
    }
    if (m_isCurrentlyRedirecting & kSTDERR) {
      unredirect(m_MetaProcessor->m_backupFDStderr, STDERR_FILENO, stderr);
    }
  }

  void MetaProcessor::MaybeRedirectOutputRAII::unredirect(int backupFD,
                                                          int expectedFD,
                                                          FILE* file) {
    // Switch back to previous file after line is processed.

    // Flush the current content if there is any.
    if (!feof(file)) {
      fflush(file);
    }
    // Copy the original fd for the std.
    if (dup2(backupFD, expectedFD) != expectedFD) {
        llvm::errs() << "cling::MetaProcessor::unredirect "
                     << "The unredirection file descriptor not valid "
                     << backupFD << ".\n";
    }
  }

  MetaProcessor::MetaProcessor(Interpreter& interp, raw_ostream& outs)
    : m_Interp(interp), m_Outs(&outs) {
    m_InputValidator.reset(new InputValidator());
    m_MetaParser.reset(new MetaParser(new MetaSema(interp, *this)));
    m_backupFDStdout = copyFileDescriptor(STDOUT_FILENO);
    m_backupFDStderr = copyFileDescriptor(STDERR_FILENO);
  }

  MetaProcessor::~MetaProcessor() {
    close(m_backupFDStdout);
    close(m_backupFDStderr);
  }

  int MetaProcessor::process(const char* input_text,
                             Interpreter::CompilationResult& compRes,
                             Value* result) {
    if (result)
      *result = Value();
    compRes = Interpreter::kSuccess;
    int expectedIndent = m_InputValidator->getExpectedIndent();

    if (expectedIndent)
      compRes = Interpreter::kMoreInputExpected;
    if (!input_text || !input_text[0]) {
      // nullptr / empty string, nothing to do.
      return expectedIndent;
    }
    std::string input_line(input_text);
    if (input_line == "\n") { // just a blank line, nothing to do.
      return expectedIndent;
    }
    //  Check for and handle meta commands.
    m_MetaParser->enterNewInputLine(input_line);
    MetaSema::ActionResult actionResult = MetaSema::AR_Success;
    if (!m_InputValidator->inBlockComment() &&
         m_MetaParser->isMetaCommand(actionResult, result)) {

      if (m_MetaParser->isQuitRequested())
        return -1;

      if (actionResult != MetaSema::AR_Success)
        compRes = Interpreter::kFailure;
       // ExpectedIndent might have changed after meta command.
       return m_InputValidator->getExpectedIndent();
    }

    // Check if the current statement is now complete. If not, return to
    // prompt for more.
    if (m_InputValidator->validate(input_line) == InputValidator::kIncomplete) {
      compRes = Interpreter::kMoreInputExpected;
      return m_InputValidator->getExpectedIndent();
    }

    //  We have a complete statement, compile and execute it.
    std::string input;
    m_InputValidator->reset(&input);
    // if (m_Options.RawInput)
    //   compResLocal = m_Interp.declare(input);
    // else
    compRes = m_Interp.process(input, result);

    return 0;
  }

  void MetaProcessor::cancelContinuation() const {
    m_InputValidator->reset();
  }

  int MetaProcessor::getExpectedIndent() const {
    return m_InputValidator->getExpectedIndent();
  }

  Interpreter::CompilationResult
  MetaProcessor::readInputFromFile(llvm::StringRef filename,
                                   Value* result,
                                   size_t posOpenCurly) {

    {
      // check that it's not binary:
      std::ifstream in(filename.str().c_str(), std::ios::in | std::ios::binary);
      char magic[1024] = {0};
      in.read(magic, sizeof(magic));
      size_t readMagic = in.gcount();
      // Binary files < 300 bytes are rare, and below newlines etc make the
      // heuristic unreliable.
      if (readMagic >= 300) {
        llvm::StringRef magicStr(magic,in.gcount());
        llvm::sys::fs::file_magic fileType
          = llvm::sys::fs::identify_magic(magicStr);
        if (fileType != llvm::sys::fs::file_magic::unknown) {
          llvm::errs() << "Error in cling::MetaProcessor: "
            "cannot read input from a binary file!\n";
          return Interpreter::kFailure;
        }
        unsigned printable = 0;
        for (size_t i = 0; i < readMagic; ++i)
          if (isprint(magic[i]))
            ++printable;
        if (10 * printable <  5 * readMagic) {
          // 50% printable for ASCII files should be a safe guess.
          llvm::errs() << "Error in cling::MetaProcessor: "
            "cannot read input from a (likely) binary file!\n" << printable;
          return Interpreter::kFailure;
        }
      }
    }

    std::ifstream in(filename.str().c_str());
    in.seekg(0, std::ios::end);
    size_t size = in.tellg();
    std::string content(size, ' ');
    in.seekg(0);
    in.read(&content[0], size);

    if (posOpenCurly != (size_t)-1 && !content.empty()) {
      assert(content[posOpenCurly] == '{'
             && "No curly at claimed position of opening curly!");
      // hide the curly brace:
      content[posOpenCurly] = ' ';
      // and the matching closing '}'
      static const char whitespace[] = " \t\r\n";
      size_t posCloseCurly = content.find_last_not_of(whitespace);
      if (posCloseCurly != std::string::npos) {
        if (content[posCloseCurly] == ';' && content[posCloseCurly-1] == '}') {
          content[posCloseCurly--] = ' '; // replace ';' and enter next if
        }
        if (content[posCloseCurly] == '}') {
          content[posCloseCurly] = ' '; // replace '}'
        } else {
          std::string::size_type posBlockClose = content.find_last_of('}');
          if (posBlockClose != std::string::npos) {
            content[posBlockClose] = ' '; // replace '}'
          }
          std::string::size_type posComment
            = content.find_first_not_of(whitespace, posBlockClose);
          if (posComment != std::string::npos
              && content[posComment] == '/' && content[posComment+1] == '/') {
            // More text (comments) are okay after the last '}', but
            // we can not easily find it to remove it (so we need to upgrade
            // this code to better handle the case with comments or
            // preprocessor code before and after the leading { and
            // trailing })
            while (posComment <= posCloseCurly) {
              content[posComment++] = ' '; // replace '}' and comment
            }
          } else {
            content[posCloseCurly] = '{';
            // By putting the '{' back, we keep the code as consistent as
            // the user wrote it ... but we should still warn that we not
            // goint to treat this file an unamed macro.
            llvm::errs()
              << "Warning in cling::MetaProcessor: can not find the closing '}', "
              << llvm::sys::path::filename(filename)
              << " is not handled as an unamed script!\n";
          } // did not find "//"
        } // remove comments after the trailing '}'
      } // find '}'
    } // ignore outermost block

    std::string strFilename(filename.str());
    m_CurrentlyExecutingFile = strFilename;
    bool topmost = !m_TopExecutingFile.data();
    if (topmost)
      m_TopExecutingFile = m_CurrentlyExecutingFile;
    Interpreter::CompilationResult ret;
    // We don't want to value print the results of a unnamed macro.
    content = "#line 2 \"" + filename.str() + "\" \n" + content;
    if (process((content + ";").c_str(), ret, result)) {
      // Input file has to be complete.
       llvm::errs()
          << "Error in cling::MetaProcessor: file "
          << llvm::sys::path::filename(filename)
          << " is incomplete (missing parenthesis or similar)!\n";
      ret = Interpreter::kFailure;
    }
    m_CurrentlyExecutingFile = llvm::StringRef();
    if (topmost)
      m_TopExecutingFile = llvm::StringRef();
    return ret;
  }

  void MetaProcessor::setFileStream(llvm::StringRef file, bool append, int fd,
              llvm::SmallVector<llvm::SmallString<128>, 2>& prevFileStack) {
    // If we have a fileName to redirect to store it.
    if (!file.empty()) {
      prevFileStack.push_back(file);
      // pop and push a null terminating 0.
      // SmallVectorImpl<T> does not have a c_str(), thus instead of casting to
      // a SmallString<T> we null terminate the data that we have and pop the
      // 0 char back.
      prevFileStack.back().push_back(0);
      prevFileStack.back().pop_back();
      if (!append) {
        FILE * f;
        if (!(f = fopen(file.data(), "w"))) {
          llvm::errs() << "cling::MetaProcessor::setFileStream:"
                       " The file path " << file.data() << " is not valid.\n";
        } else {
          fclose(f);
        }
      }
    // Else unredirection, so switch to the previous file.
    } else {
      // If there is no previous file on the stack we pop the file
      if (!prevFileStack.empty()) {
        prevFileStack.pop_back();
      }
    }
  }

  void MetaProcessor::setStdStream(llvm::StringRef file,
                                   RedirectionScope stream, bool append) {

    if (stream & kSTDOUT) {
      setFileStream(file, append, STDOUT_FILENO, m_PrevStdoutFileName);
    }
    if (stream & kSTDERR) {
      setFileStream(file, append, STDERR_FILENO, m_PrevStderrFileName);
    }
  }

  int MetaProcessor::copyFileDescriptor(int fd) {
    int backupFD = dup(fd);
    if (backupFD < 0) {
      llvm::errs() << "MetaProcessor::copyFileDescriptor: Duplicating the file"
                   " descriptor " << fd << " resulted in an error."
                   " Will not be able to unredirect.\n";
    }
    return backupFD;
  }

  void MetaProcessor::registerUnloadPoint(const Transaction* T,
                                          llvm::StringRef filename) {
    m_MetaParser->getActions().registerUnloadPoint(T, filename);
  }

} // end namespace cling
<commit_msg>Add error handling to MetaProcessor::readInputFromFile.<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Axel Naumann <axel@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "cling/MetaProcessor/MetaProcessor.h"

#include "Display.h"
#include "InputValidator.h"
#include "MetaParser.h"
#include "MetaSema.h"
#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/Value.h"

#include "clang/Basic/FileManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"

#include "llvm/Support/Path.h"

#include <fstream>
#include <cstdlib>
#include <cctype>
#include <stdio.h>
#ifndef WIN32
#include <unistd.h>
#else
#include <io.h>
#define STDIN_FILENO  0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
#endif

using namespace clang;

namespace cling {

  MetaProcessor::MaybeRedirectOutputRAII::MaybeRedirectOutputRAII(
                                          MetaProcessor* p)
  :m_MetaProcessor(p), m_isCurrentlyRedirecting(0) {
    StringRef redirectionFile;
    m_MetaProcessor->increaseRedirectionRAIILevel();
    if (!m_MetaProcessor->m_PrevStdoutFileName.empty()) {
      redirectionFile = m_MetaProcessor->m_PrevStdoutFileName.back();
      redirect(stdout, redirectionFile.str(), kSTDOUT);
    }
    if (!m_MetaProcessor->m_PrevStderrFileName.empty()) {
      redirectionFile = m_MetaProcessor->m_PrevStderrFileName.back();
      // Deal with the case 2>&1 and 2&>1
      if (strcmp(redirectionFile.data(), "_IO_2_1_stdout_") == 0) {
        // If out is redirected to a file.
        if (!m_MetaProcessor->m_PrevStdoutFileName.empty()) {
          redirectionFile = m_MetaProcessor->m_PrevStdoutFileName.back();
        } else {
          unredirect(m_MetaProcessor->m_backupFDStderr, STDERR_FILENO, stderr);
        }
      }
      redirect(stderr, redirectionFile.str(), kSTDERR);
    }
  }

  MetaProcessor::MaybeRedirectOutputRAII::~MaybeRedirectOutputRAII() {
    pop();
    m_MetaProcessor->decreaseRedirectionRAIILevel();
  }

  void MetaProcessor::MaybeRedirectOutputRAII::redirect(FILE* file,
                                        const std::string& fileName,
                                        MetaProcessor::RedirectionScope scope) {
    if (!fileName.empty()) {
      FILE* redirectionFile = freopen(fileName.c_str(), "a", file);
      if (!redirectionFile) {
        llvm::errs()<<"cling::MetaProcessor::MaybeRedirectOutputRAII::redirect:"
                    " Not succefully reopened the redirection file "
                    << fileName.c_str() << "\n.";
      } else {
        m_isCurrentlyRedirecting |= scope;
      }
    }
  }

  void MetaProcessor::MaybeRedirectOutputRAII::pop() {
    //If we have only one redirection RAII
    //only then do the unredirection.
    if (m_MetaProcessor->getRedirectionRAIILevel() != 1)
      return;

    if (m_isCurrentlyRedirecting & kSTDOUT) {
      unredirect(m_MetaProcessor->m_backupFDStdout, STDOUT_FILENO, stdout);
    }
    if (m_isCurrentlyRedirecting & kSTDERR) {
      unredirect(m_MetaProcessor->m_backupFDStderr, STDERR_FILENO, stderr);
    }
  }

  void MetaProcessor::MaybeRedirectOutputRAII::unredirect(int backupFD,
                                                          int expectedFD,
                                                          FILE* file) {
    // Switch back to previous file after line is processed.

    // Flush the current content if there is any.
    if (!feof(file)) {
      fflush(file);
    }
    // Copy the original fd for the std.
    if (dup2(backupFD, expectedFD) != expectedFD) {
        llvm::errs() << "cling::MetaProcessor::unredirect "
                     << "The unredirection file descriptor not valid "
                     << backupFD << ".\n";
    }
  }

  MetaProcessor::MetaProcessor(Interpreter& interp, raw_ostream& outs)
    : m_Interp(interp), m_Outs(&outs) {
    m_InputValidator.reset(new InputValidator());
    m_MetaParser.reset(new MetaParser(new MetaSema(interp, *this)));
    m_backupFDStdout = copyFileDescriptor(STDOUT_FILENO);
    m_backupFDStderr = copyFileDescriptor(STDERR_FILENO);
  }

  MetaProcessor::~MetaProcessor() {
    close(m_backupFDStdout);
    close(m_backupFDStderr);
  }

  int MetaProcessor::process(const char* input_text,
                             Interpreter::CompilationResult& compRes,
                             Value* result) {
    if (result)
      *result = Value();
    compRes = Interpreter::kSuccess;
    int expectedIndent = m_InputValidator->getExpectedIndent();

    if (expectedIndent)
      compRes = Interpreter::kMoreInputExpected;
    if (!input_text || !input_text[0]) {
      // nullptr / empty string, nothing to do.
      return expectedIndent;
    }
    std::string input_line(input_text);
    if (input_line == "\n") { // just a blank line, nothing to do.
      return expectedIndent;
    }
    //  Check for and handle meta commands.
    m_MetaParser->enterNewInputLine(input_line);
    MetaSema::ActionResult actionResult = MetaSema::AR_Success;
    if (!m_InputValidator->inBlockComment() &&
         m_MetaParser->isMetaCommand(actionResult, result)) {

      if (m_MetaParser->isQuitRequested())
        return -1;

      if (actionResult != MetaSema::AR_Success)
        compRes = Interpreter::kFailure;
       // ExpectedIndent might have changed after meta command.
       return m_InputValidator->getExpectedIndent();
    }

    // Check if the current statement is now complete. If not, return to
    // prompt for more.
    if (m_InputValidator->validate(input_line) == InputValidator::kIncomplete) {
      compRes = Interpreter::kMoreInputExpected;
      return m_InputValidator->getExpectedIndent();
    }

    //  We have a complete statement, compile and execute it.
    std::string input;
    m_InputValidator->reset(&input);
    // if (m_Options.RawInput)
    //   compResLocal = m_Interp.declare(input);
    // else
    compRes = m_Interp.process(input, result);

    return 0;
  }

  void MetaProcessor::cancelContinuation() const {
    m_InputValidator->reset();
  }

  int MetaProcessor::getExpectedIndent() const {
    return m_InputValidator->getExpectedIndent();
  }

  static Interpreter::CompilationResult reportIOErr(llvm::StringRef File,
                                                    const char* What) {
    llvm::errs() << "Error in cling::MetaProcessor: "
          "cannot " << What << " input: '" << File << "'\n";
    return Interpreter::kFailure;
  }

  Interpreter::CompilationResult
  MetaProcessor::readInputFromFile(llvm::StringRef filename,
                                   Value* result,
                                   size_t posOpenCurly) {

    // FIXME: This will fail for Unicode BOMs (and seems really weird)
    {
      // check that it's not binary:
      std::ifstream in(filename.str().c_str(), std::ios::in | std::ios::binary);
      if (in.fail())
        return reportIOErr(filename, "open");

      char magic[1024] = {0};
      in.read(magic, sizeof(magic));
      size_t readMagic = in.gcount();
      // Binary files < 300 bytes are rare, and below newlines etc make the
      // heuristic unreliable.
      if (!in.fail() && readMagic >= 300) {
        llvm::StringRef magicStr(magic,in.gcount());
        llvm::sys::fs::file_magic fileType
          = llvm::sys::fs::identify_magic(magicStr);
        if (fileType != llvm::sys::fs::file_magic::unknown)
          return reportIOErr(filename, "read from binary");

        unsigned printable = 0;
        for (size_t i = 0; i < readMagic; ++i)
          if (isprint(magic[i]))
            ++printable;
        if (10 * printable <  5 * readMagic) {
          // 50% printable for ASCII files should be a safe guess.
          return reportIOErr(filename, "won't read from likely binary");
        }
      }
    }

    std::ifstream in(filename.str().c_str());
    if (in.fail())
      return reportIOErr(filename, "open");

    in.seekg(0, std::ios::end);
    if (in.fail())
      return reportIOErr(filename, "seek");

    size_t size = in.tellg();
    if (in.fail())
      return reportIOErr(filename, "tell");

    in.seekg(0);
    if (in.fail())
      return reportIOErr(filename, "rewind");

    std::string content(size, ' ');
    in.read(&content[0], size);
    if (in.fail())
      return reportIOErr(filename, "read");

    if (posOpenCurly != (size_t)-1 && !content.empty()) {
      assert(content[posOpenCurly] == '{'
             && "No curly at claimed position of opening curly!");
      // hide the curly brace:
      content[posOpenCurly] = ' ';
      // and the matching closing '}'
      static const char whitespace[] = " \t\r\n";
      size_t posCloseCurly = content.find_last_not_of(whitespace);
      if (posCloseCurly != std::string::npos) {
        if (content[posCloseCurly] == ';' && content[posCloseCurly-1] == '}') {
          content[posCloseCurly--] = ' '; // replace ';' and enter next if
        }
        if (content[posCloseCurly] == '}') {
          content[posCloseCurly] = ' '; // replace '}'
        } else {
          std::string::size_type posBlockClose = content.find_last_of('}');
          if (posBlockClose != std::string::npos) {
            content[posBlockClose] = ' '; // replace '}'
          }
          std::string::size_type posComment
            = content.find_first_not_of(whitespace, posBlockClose);
          if (posComment != std::string::npos
              && content[posComment] == '/' && content[posComment+1] == '/') {
            // More text (comments) are okay after the last '}', but
            // we can not easily find it to remove it (so we need to upgrade
            // this code to better handle the case with comments or
            // preprocessor code before and after the leading { and
            // trailing })
            while (posComment <= posCloseCurly) {
              content[posComment++] = ' '; // replace '}' and comment
            }
          } else {
            content[posCloseCurly] = '{';
            // By putting the '{' back, we keep the code as consistent as
            // the user wrote it ... but we should still warn that we not
            // goint to treat this file an unamed macro.
            llvm::errs()
              << "Warning in cling::MetaProcessor: can not find the closing '}', "
              << llvm::sys::path::filename(filename)
              << " is not handled as an unamed script!\n";
          } // did not find "//"
        } // remove comments after the trailing '}'
      } // find '}'
    } // ignore outermost block

    m_CurrentlyExecutingFile = filename;
    bool topmost = !m_TopExecutingFile.data();
    if (topmost)
      m_TopExecutingFile = m_CurrentlyExecutingFile;
    Interpreter::CompilationResult ret;
    // We don't want to value print the results of a unnamed macro.
    content = "#line 2 \"" + filename.str() + "\" \n" + content;
    if (process((content + ";").c_str(), ret, result)) {
      // Input file has to be complete.
       llvm::errs()
          << "Error in cling::MetaProcessor: file "
          << llvm::sys::path::filename(filename)
          << " is incomplete (missing parenthesis or similar)!\n";
      ret = Interpreter::kFailure;
    }
    m_CurrentlyExecutingFile = llvm::StringRef();
    if (topmost)
      m_TopExecutingFile = llvm::StringRef();
    return ret;
  }

  void MetaProcessor::setFileStream(llvm::StringRef file, bool append, int fd,
              llvm::SmallVector<llvm::SmallString<128>, 2>& prevFileStack) {
    // If we have a fileName to redirect to store it.
    if (!file.empty()) {
      prevFileStack.push_back(file);
      // pop and push a null terminating 0.
      // SmallVectorImpl<T> does not have a c_str(), thus instead of casting to
      // a SmallString<T> we null terminate the data that we have and pop the
      // 0 char back.
      prevFileStack.back().push_back(0);
      prevFileStack.back().pop_back();
      if (!append) {
        FILE * f;
        if (!(f = fopen(file.data(), "w"))) {
          llvm::errs() << "cling::MetaProcessor::setFileStream:"
                       " The file path " << file.data() << " is not valid.\n";
        } else {
          fclose(f);
        }
      }
    // Else unredirection, so switch to the previous file.
    } else {
      // If there is no previous file on the stack we pop the file
      if (!prevFileStack.empty()) {
        prevFileStack.pop_back();
      }
    }
  }

  void MetaProcessor::setStdStream(llvm::StringRef file,
                                   RedirectionScope stream, bool append) {

    if (stream & kSTDOUT) {
      setFileStream(file, append, STDOUT_FILENO, m_PrevStdoutFileName);
    }
    if (stream & kSTDERR) {
      setFileStream(file, append, STDERR_FILENO, m_PrevStderrFileName);
    }
  }

  int MetaProcessor::copyFileDescriptor(int fd) {
    int backupFD = dup(fd);
    if (backupFD < 0) {
      llvm::errs() << "MetaProcessor::copyFileDescriptor: Duplicating the file"
                   " descriptor " << fd << " resulted in an error."
                   " Will not be able to unredirect.\n";
    }
    return backupFD;
  }

  void MetaProcessor::registerUnloadPoint(const Transaction* T,
                                          llvm::StringRef filename) {
    m_MetaParser->getActions().registerUnloadPoint(T, filename);
  }

} // end namespace cling
<|endoftext|>


<commit_before>#ifndef INCLUDE_AL_GRAPHICS_STEREOGRAPHIC_HPP
#define INCLUDE_AL_GRAPHICS_STEREOGRAPHIC_HPP

/*
 *  A collection of functions and classes related to application mainloops
 *  AlloSphere Research Group / Media Arts & Technology, UCSB, 2009
 */

/*
	Copyright (C) 2006-2008. The Regents of the University of California (REGENTS).
	All Rights Reserved.

	Permission to use, copy, modify, distribute, and distribute modified versions
	of this software and its documentation without fee and without a signed
	licensing agreement, is hereby granted, provided that the above copyright
	notice, the list of contributors, this paragraph and the following two paragraphs
	appear in all copies, modifications, and distributions.

	IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
	SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
	OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
	BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

	REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
	THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
	PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
	HEREUNDER IS PROVIDED "AS IS". REGENTS HAS  NO OBLIGATION TO PROVIDE
	MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/

#include "allocore/protocol/al_Graphics.hpp"
#include "allocore/spatial/al_Camera.hpp"

namespace al {
namespace gfx{

/// A framed area on a display screen
struct Viewport {
	int l, b, w, h;	///< left, bottom, width, height

	Viewport(int w=0, int h=1) : b(0), l(0), w(w), h(h) {}
	Viewport(int l, int b, int w, int h) : l(l), b(b), w(w), h(h) {}

	double aspect() { return w/(double)h; }
};

///	Higher-level utility class to manage various stereo rendering techniques
class Stereographic {
public:
	enum StereoMode{
		Anaglyph=0,	/**< Red (left eye) / cyan (right eye) stereo */
		Active,		/**< Active quad-buffered stereo */
		Dual,		/**< Dual side-by-side stereo */
		LeftEye,	/**< Left eye only */
		RightEye	/**< Right eye only */
	};
	enum AnaglyphMode {
		RedBlue = 0,
		RedGreen,
		RedCyan,
		BlueRed,
		GreenRed,
		CyanRed
	};

	Stereographic()
	: mMode(Anaglyph), mAnaglyphMode(RedBlue), mStereo(false) {}
	~Stereographic() {}

	///< draw the scene according to the stored stereographic mode
	void draw(Graphics& gl, Camera& cam, Pose& pose, Viewport& viewport, Drawable& draw);

	/// So many different ways to draw :-)
	void drawMono(Graphics& gl, Camera& cam, Pose& pose, Viewport& viewport, Drawable& draw);
	void drawActive(Graphics& gl, Camera& cam, Pose& pose, Viewport& viewport, Drawable& draw);
	void drawAnaglyph(Graphics& gl, Camera& cam, Pose& pose, Viewport& viewport, Drawable& draw);
	void drawDual(Graphics& gl, Camera& cam, Pose& pose, Viewport& viewport, Drawable& draw);
	void drawLeft(Graphics& gl, Camera& cam, Pose& pose, Viewport& viewport, Drawable& draw);
	void drawRight(Graphics& gl, Camera& cam, Pose& pose, Viewport& viewport, Drawable& draw);

	/// Blue line sync for active stereo (for those projectors that need it)
	/// add this call at the end of rendering (just before the swap buffers call)
	void drawBlueLine(double window_width, double window_height);

	Stereographic& mode(StereoMode v){ mMode=v; return *this; }	///< Set stereographic mode
	Stereographic& stereo(bool v){ mStereo=v; return *this; }		///< Set stereographic active
	Stereographic& anaglyphMode(AnaglyphMode v) { mAnaglyphMode=v; return *this; }	///< set glasses type

	StereoMode mode() const { return mMode; }				///< Get stereographic mode
	bool stereo() const { return mStereo; }					///< Get stereographic active
	AnaglyphMode anaglyphMode() const { return mAnaglyphMode; }	///< get anaglyph glasses type

protected:
	StereoMode mMode;
	AnaglyphMode mAnaglyphMode;
	bool mStereo;
};

} // gfx::
} // al::

#endif /* include guard */
<commit_msg>updates to Viewport<commit_after>#ifndef INCLUDE_AL_GRAPHICS_STEREOGRAPHIC_HPP
#define INCLUDE_AL_GRAPHICS_STEREOGRAPHIC_HPP

/*
 *  A collection of functions and classes related to application mainloops
 *  AlloSphere Research Group / Media Arts & Technology, UCSB, 2009
 */

/*
	Copyright (C) 2006-2008. The Regents of the University of California (REGENTS).
	All Rights Reserved.

	Permission to use, copy, modify, distribute, and distribute modified versions
	of this software and its documentation without fee and without a signed
	licensing agreement, is hereby granted, provided that the above copyright
	notice, the list of contributors, this paragraph and the following two paragraphs
	appear in all copies, modifications, and distributions.

	IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
	SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
	OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
	BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

	REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
	THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
	PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
	HEREUNDER IS PROVIDED "AS IS". REGENTS HAS  NO OBLIGATION TO PROVIDE
	MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/

#include "allocore/protocol/al_Graphics.hpp"
#include "allocore/spatial/al_Camera.hpp"

namespace al {
namespace gfx{

/// A framed area on a display screen
struct Viewport {
	int l, b, w, h;	///< left, bottom, width, height

	Viewport(int w=0, int h=1) : b(0), l(0), w(w), h(h) {}
	Viewport(int l, int b, int w, int h) : l(l), b(b), w(w), h(h) {}

	/// Get aspect ratio
	double aspect() const { return w/(double)h; }

	/// Set dimensions
	void set(int l_, int b_, int w_, int h_){ l=l_; b=b_; w=w_; h=h_; }
};

///	Higher-level utility class to manage various stereo rendering techniques
class Stereographic {
public:
	enum StereoMode{
		Anaglyph=0,	/**< Red (left eye) / cyan (right eye) stereo */
		Active,		/**< Active quad-buffered stereo */
		Dual,		/**< Dual side-by-side stereo */
		LeftEye,	/**< Left eye only */
		RightEye	/**< Right eye only */
	};
	enum AnaglyphMode {
		RedBlue = 0,
		RedGreen,
		RedCyan,
		BlueRed,
		GreenRed,
		CyanRed
	};

	Stereographic()
	: mMode(Anaglyph), mAnaglyphMode(RedBlue), mStereo(false) {}
	~Stereographic() {}

	///< draw the scene according to the stored stereographic mode
	void draw(Graphics& gl, Camera& cam, Pose& pose, Viewport& viewport, Drawable& draw);

	/// So many different ways to draw :-)
	void drawMono(Graphics& gl, Camera& cam, Pose& pose, Viewport& viewport, Drawable& draw);
	void drawActive(Graphics& gl, Camera& cam, Pose& pose, Viewport& viewport, Drawable& draw);
	void drawAnaglyph(Graphics& gl, Camera& cam, Pose& pose, Viewport& viewport, Drawable& draw);
	void drawDual(Graphics& gl, Camera& cam, Pose& pose, Viewport& viewport, Drawable& draw);
	void drawLeft(Graphics& gl, Camera& cam, Pose& pose, Viewport& viewport, Drawable& draw);
	void drawRight(Graphics& gl, Camera& cam, Pose& pose, Viewport& viewport, Drawable& draw);

	/// Blue line sync for active stereo (for those projectors that need it)
	/// add this call at the end of rendering (just before the swap buffers call)
	void drawBlueLine(double window_width, double window_height);

	Stereographic& mode(StereoMode v){ mMode=v; return *this; }	///< Set stereographic mode
	Stereographic& stereo(bool v){ mStereo=v; return *this; }		///< Set stereographic active
	Stereographic& anaglyphMode(AnaglyphMode v) { mAnaglyphMode=v; return *this; }	///< set glasses type

	StereoMode mode() const { return mMode; }				///< Get stereographic mode
	bool stereo() const { return mStereo; }					///< Get stereographic active
	AnaglyphMode anaglyphMode() const { return mAnaglyphMode; }	///< get anaglyph glasses type

protected:
	StereoMode mMode;
	AnaglyphMode mAnaglyphMode;
	bool mStereo;
};

} // gfx::
} // al::

#endif /* include guard */
<|endoftext|>


<commit_before>// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#ifndef MFEM_NAVIER_SOLVER_HPP
#define MFEM_NAVIER_SOLVER_HPP

#define NAVIER_VERSION 0.1

#include "mfem.hpp"
#include "ortho_solver.hpp"

namespace mfem
{
namespace navier
{
using VecFuncT = void(const Vector &x, double t, Vector &u);
using ScalarFuncT = double(const Vector &x, double t);

/// Container for a Dirichlet boundary condition of the velocity field.
class VelDirichletBC_T
{
public:
   VelDirichletBC_T(Array<int> attr, VectorCoefficient *coeff)
      : attr(attr), coeff(coeff)
   {}

   VelDirichletBC_T(VelDirichletBC_T &&obj)
   {
      // Deep copy the attribute array
      this->attr = obj.attr;

      // Move the coefficient pointer
      this->coeff = obj.coeff;
      obj.coeff = nullptr;
   }

   ~VelDirichletBC_T() { delete coeff; }

   Array<int> attr;
   VectorCoefficient *coeff;
};

/// Container for a Dirichlet boundary condition of the pressure field.
class PresDirichletBC_T
{
public:
   PresDirichletBC_T(Array<int> attr, Coefficient *coeff)
      : attr(attr), coeff(coeff)
   {}

   PresDirichletBC_T(PresDirichletBC_T &&obj)
   {
      // Deep copy the attribute array
      this->attr = obj.attr;

      // Move the coefficient pointer
      this->coeff = obj.coeff;
      obj.coeff = nullptr;
   }

   ~PresDirichletBC_T() { delete coeff; }

   Array<int> attr;
   Coefficient *coeff;
};

/// Container for an acceleration term.
class AccelTerm_T
{
public:
   AccelTerm_T(Array<int> attr, VectorCoefficient *coeff)
      : attr(attr), coeff(coeff)
   {}

   AccelTerm_T(AccelTerm_T &&obj)
   {
      // Deep copy the attribute array
      this->attr = obj.attr;

      // Move the coefficient pointer
      this->coeff = obj.coeff;
      obj.coeff = nullptr;
   }

   ~AccelTerm_T() { delete coeff; }

   Array<int> attr;
   VectorCoefficient *coeff;
};

/// Transient incompressible Navier Stokes solver in a split scheme formulation.
/**
 * This implementation of a transient incompressible Navier Stokes solver uses
 * the non-dimensionalized formulation. The coupled momentum and
 * incompressibilty equations are decoupled using the split scheme described in
 * [1]. This leads to three solving steps.
 *
 * 1. An extrapolation step for all nonlinear terms which are treated
 *    explicitly. This step avoids a fully coupled nonlinear solve and only
 *    requires a solve of the mass matrix in velocity space \f$M_v^{-1}\f$. On
 *    the other hand this introduces a CFL stability condition on the maximum
 *    timestep.
 *
 * 2. A Poisson solve \f$S_p^{-1}\f$.
 *
 * 3. A Helmholtz like solve \f$(M_v - \partial t K_v)^{-1}\f$.
 *
 * The numerical solver setup for each step are as follows.
 *
 * \f$M_v^{-1}\f$ is solved using CG with Jacobi as preconditioner.
 *
 * \f$S_p^{-1}\f$ is solved using CG with AMG applied to the low order refined
 * (LOR) assembled pressure poisson matrix. To avoid assembling a matrix for
 * preconditioning, one can use p-MG as an alternative (NYI).
 *
 * \f$(M_v - \partial t K_v)^{-1}\f$ due to the CFL condition we expect the time
 * step to be small. Therefore this is solved using CG with Jacobi as
 * preconditioner. For large time steps a preconditioner like AMG or p-MG should
 * be used (NYI).
 *
 * Statements marked with NYI mean this feature is planned but Not Yet
 * Implemented.
 *
 * A detailed description is available in [1] section 4.2. The algorithm is
 * originated from [2].
 *
 * [1] Michael Franco, Jean-Sylvain Camier, Julian Andrej, Will Pazner (2020)
 * High-order matrix-free incompressible flow solvers with GPU acceleration and
 * low-order refined preconditioners (https://arxiv.org/abs/1910.03032)
 *
 * [2] A. G. Tomboulides, J. C. Y. Lee & S. A. Orszag (1997) Numerical
 * Simulation of Low Mach Number Reactive Flows
 */
class NavierSolver
{
public:
   /// Initialize data structures, set FE space order and kinematic viscosity.
   /**
    * The ParMesh @a mesh can be a linear or curved parallel mesh. The @a order
    * of the finite element spaces is this algorithm is of equal order
    * \f$(P_N)^d P_N\f$ for velocity and pressure respectively. This means the
    * pressure is in discretized in the same space (just scalar instead of a
    * vector space) as the velocity.
    *
    * Kinematic viscosity (dimensionless) is set using @a kin_vis and
    * automatically converted to the Reynolds number. If you want to set the
    * Reynolds number directly, you can provide the inverse.
    */
   NavierSolver(ParMesh *mesh, int order, double kin_vis);

   /// Initialize forms, solvers and preconditioners.
   void Setup(double dt);

   /// Compute solution at the next time step t+dt.
   void Step(double &time, double dt, int cur_step);

   /// Return a pointer to the current velocity ParGridFunction.
   ParGridFunction *GetCurrentVelocity() { return &un_gf; }

   /// Return a pointer to the current pressure ParGridFunction.
   ParGridFunction *GetCurrentPressure() { return &pn_gf; }

   /// Add a Dirichlet boundary condition to the velocity field.
   void AddVelDirichletBC(VectorCoefficient *coeff, Array<int> &attr);

   void AddVelDirichletBC(VecFuncT *f, Array<int> &attr);

   /// Add a Dirichlet boundary condition to the pressure field.
   void AddPresDirichletBC(Coefficient *coeff, Array<int> &attr);

   void AddPresDirichletBC(ScalarFuncT *f, Array<int> &attr);

   /// Add an accelaration term to the RHS of the equation.
   /**
    * The VecFuncT @a f is evaluated at the current time t and extrapolated
    * together with the nonlinear parts of the Navier Stokes equation.
    */
   void AddAccelTerm(VectorCoefficient *coeff, Array<int> &attr);

   void AddAccelTerm(VecFuncT *f, Array<int> &attr);

   /// Enable partial assembly for every operator.
   void EnablePA(bool pa) { partial_assembly = pa; }

   /// Enable numerical integration rules. This means collocated quadrature at
   /// the nodal points.
   void EnableNI(bool ni) { numerical_integ = ni; }

   /// Print timing summary of the solving routine.
   /**
    * The summary shows the timing in seconds in the first row of
    *
    * 1. SETUP: Time spent for the setup of all forms, solvers and
    *    preconditioners.
    * 2. STEP: Time spent computing a full time step. It includes allthree
    *    solves.
    * 3. EXTRAP: Time spent for extrapolation of all forcing and nonlinear
    *    terms.
    * 4. CURLCURL: Time spent for computing the curl curl term in the pressure
    *    Poisson equation (see references for detailed explanation).
    * 5. PSOLVE: Time spent in the pressure Poisson solve.
    * 6. HSOLVE: Time spent in the Helmholtz solve.
    *
    * The second row shows a proportion of a column relative to the whole
    * time step.
    */
   void PrintTimingData();

   ~NavierSolver();

   /// Compute \f$\nabla \times \nabla \times u\f$ for \f$u \in (H^1)^2\f$.
   void ComputeCurl2D(ParGridFunction &u,
                      ParGridFunction &cu,
                      bool assume_scalar = false);

   /// Compute \f$\nabla \times \nabla \times u\f$ for \f$u \in (H^1)^3\f$.
   void ComputeCurl3D(ParGridFunction &u, ParGridFunction &cu);

   /// Remove mean from a Vector.
   /**
    * Modify the Vector @a v by subtracting its mean using
    * \f$v = v - \frac{\sum_i^N v_i}{N} \f$
    */
   void Orthogonalize(Vector &v);

   /// Remove the mean from a ParGridFunction.
   /**
    * Modify the ParGridFunction @a v by subtracting its mean using
    * \f$ v = v - \int_\Omega \frac{v}{vol(\Omega)} dx \f$.
    */
   void MeanZero(ParGridFunction &v);

   /// Compute CFL
   double ComputeCFL(ParGridFunction &u, double dt);

   /// Set the number of modes to cut off in the interpolation filter
   void SetCutoffModes(int c) { filter_cutoff_modes = c; }

   /// Set the interpolation filter parameter @a alpha
   /**
    * If the @a a is > 0, the filtering algorithm for the velocity field after
    * every time step from [1] is used.
    *
    * [1] Paul Fischer, Julia Mullen: Filter-based stabilization of spectral
    * element methods
    */
   void SetFilterAlpha(double a) { filter_alpha = a; }

protected:
   /// Print informations about the Navier version.
   void PrintInfo();

   /// Update the EXTk/BDF time integration coefficient.
   /**
    * Depending on which time step the computation is in, the EXTk/BDF time
    * integration coefficients have to be set accordingly. This allows
    * bootstrapping with a BDF scheme of order 1 and increasing the order each
    * following time step, up to order 3.
    */
   void SetTimeIntegrationCoefficients(int step);

   /// Eliminate essential BCs in an Operator and apply to RHS.
   void EliminateRHS(Operator &A,
                     ConstrainedOperator &constrainedA,
                     const Array<int> &ess_tdof_list,
                     Vector &x,
                     Vector &b,
                     Vector &X,
                     Vector &B,
                     int copy_interior = 0);

   /// Enable/disable debug output.
   bool debug = false;

   /// Enable/disable verbose output.
   bool verbose = true;

   /// Enable/disable partial assembly of forms.
   bool partial_assembly = false;

   /// Enable/disable numerical integration rules of forms.
   bool numerical_integ = false;

   /// The parallel mesh.
   ParMesh *pmesh = nullptr;

   /// The order of the velocity and pressure space.
   int order;

   /// Kinematic viscosity (dimensionless).
   double kin_vis;

   /// Velocity \f$H^1\f$ finite element collection.
   FiniteElementCollection *vfec = nullptr;

   /// Pressure \f$H^1\f$ finite element collection.
   FiniteElementCollection *pfec = nullptr;

   /// Velocity \f$(H^1)^d\f$ finite element space.
   ParFiniteElementSpace *vfes = nullptr;

   /// Pressure \f$H^1\f$ finite element space.
   ParFiniteElementSpace *pfes = nullptr;

   ParNonlinearForm *N = nullptr;

   ParBilinearForm *Mv_form = nullptr;

   ParBilinearForm *Sp_form = nullptr;

   ParMixedBilinearForm *D_form = nullptr;

   ParMixedBilinearForm *G_form = nullptr;

   ParBilinearForm *H_form = nullptr;

   VectorGridFunctionCoefficient *FText_gfcoeff = nullptr;

   ParLinearForm *FText_bdr_form = nullptr;

   ParLinearForm *f_form = nullptr;

   ParLinearForm *g_bdr_form = nullptr;

   /// Linear form to compute the mass matrix in various subroutines.
   ParLinearForm *mass_lf = nullptr;
   ConstantCoefficient onecoeff;
   double volume = 0.0;

   ConstantCoefficient nlcoeff;
   ConstantCoefficient Sp_coeff;
   ConstantCoefficient H_lincoeff;
   ConstantCoefficient H_bdfcoeff;

   OperatorHandle Mv;
   OperatorHandle Sp;
   OperatorHandle D;
   OperatorHandle G;
   OperatorHandle H;

   Solver *MvInvPC = nullptr;
   CGSolver *MvInv = nullptr;

   HypreBoomerAMG *SpInvPC = nullptr;
   OrthoSolver *SpInvOrthoPC = nullptr;
   CGSolver *SpInv = nullptr;

   Solver *HInvPC = nullptr;
   CGSolver *HInv = nullptr;

   Vector fn, un, unm1, unm2, Nun, Nunm1, Nunm2, Fext, FText, Lext, resu;
   Vector tmp1;

   Vector pn, resp, FText_bdr, g_bdr;

   ParGridFunction un_gf, curlu_gf, curlcurlu_gf, Lext_gf, FText_gf, resu_gf;

   ParGridFunction pn_gf, resp_gf;

   // All essential attributes.
   Array<int> vel_ess_attr;
   Array<int> pres_ess_attr;

   // All essential true dofs.
   Array<int> vel_ess_tdof;
   Array<int> pres_ess_tdof;

   // Bookkeeping for velocity dirichlet bcs.
   std::vector<VelDirichletBC_T> vel_dbcs;

   // Bookkeeping for pressure dirichlet bcs.
   std::vector<PresDirichletBC_T> pres_dbcs;

   // Bookkeeping for acceleration (forcing) terms.
   std::vector<AccelTerm_T> accel_terms;

   int cur_step = 0;

   // BDFk/EXTk coefficients.
   double bd0 = 0.0;
   double bd1 = 0.0;
   double bd2 = 0.0;
   double bd3 = 0.0;
   double ab1 = 0.0;
   double ab2 = 0.0;
   double ab3 = 0.0;

   // Timers.
   StopWatch sw_setup, sw_step, sw_extrap, sw_curlcurl, sw_spsolve, sw_hsolve;

   // Print levels.
   int pl_mvsolve = 0;
   int pl_spsolve = 0;
   int pl_hsolve = 0;
   int pl_amg = 0;

   // Relative tolerances.
   double rtol_spsolve = 1e-6;
   double rtol_hsolve = 1e-8;

   // Iteration counts.
   int iter_mvsolve = 0, iter_spsolve = 0, iter_hsolve = 0;

   // Residuals.
   double res_mvsolve = 0.0, res_spsolve = 0.0, res_hsolve = 0.0;

   // LOR related.
   ParMesh *pmesh_lor = nullptr;
   FiniteElementCollection *pfec_lor = nullptr;
   ParFiniteElementSpace *pfes_lor = nullptr;
   InterpolationGridTransfer *vgt = nullptr, *pgt = nullptr;

   ParBilinearForm *Mv_form_lor = nullptr;
   ParBilinearForm *Sp_form_lor = nullptr;
   ParBilinearForm *H_form_lor = nullptr;

   OperatorHandle Mv_lor;
   OperatorHandle Sp_lor;
   OperatorHandle H_lor;

   // Filter-based stabilization
   int filter_cutoff_modes = 1;
   double filter_alpha = 0.0;
   FiniteElementCollection *vfec_filter = nullptr;
   ParFiniteElementSpace *vfes_filter = nullptr;
   ParGridFunction un_NM1_gf;
   ParGridFunction un_filtered_gf;
};
} // namespace navier
} // namespace mfem
#endif
<commit_msg>spelling<commit_after>// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#ifndef MFEM_NAVIER_SOLVER_HPP
#define MFEM_NAVIER_SOLVER_HPP

#define NAVIER_VERSION 0.1

#include "mfem.hpp"
#include "ortho_solver.hpp"

namespace mfem
{
namespace navier
{
using VecFuncT = void(const Vector &x, double t, Vector &u);
using ScalarFuncT = double(const Vector &x, double t);

/// Container for a Dirichlet boundary condition of the velocity field.
class VelDirichletBC_T
{
public:
   VelDirichletBC_T(Array<int> attr, VectorCoefficient *coeff)
      : attr(attr), coeff(coeff)
   {}

   VelDirichletBC_T(VelDirichletBC_T &&obj)
   {
      // Deep copy the attribute array
      this->attr = obj.attr;

      // Move the coefficient pointer
      this->coeff = obj.coeff;
      obj.coeff = nullptr;
   }

   ~VelDirichletBC_T() { delete coeff; }

   Array<int> attr;
   VectorCoefficient *coeff;
};

/// Container for a Dirichlet boundary condition of the pressure field.
class PresDirichletBC_T
{
public:
   PresDirichletBC_T(Array<int> attr, Coefficient *coeff)
      : attr(attr), coeff(coeff)
   {}

   PresDirichletBC_T(PresDirichletBC_T &&obj)
   {
      // Deep copy the attribute array
      this->attr = obj.attr;

      // Move the coefficient pointer
      this->coeff = obj.coeff;
      obj.coeff = nullptr;
   }

   ~PresDirichletBC_T() { delete coeff; }

   Array<int> attr;
   Coefficient *coeff;
};

/// Container for an acceleration term.
class AccelTerm_T
{
public:
   AccelTerm_T(Array<int> attr, VectorCoefficient *coeff)
      : attr(attr), coeff(coeff)
   {}

   AccelTerm_T(AccelTerm_T &&obj)
   {
      // Deep copy the attribute array
      this->attr = obj.attr;

      // Move the coefficient pointer
      this->coeff = obj.coeff;
      obj.coeff = nullptr;
   }

   ~AccelTerm_T() { delete coeff; }

   Array<int> attr;
   VectorCoefficient *coeff;
};

/// Transient incompressible Navier Stokes solver in a split scheme formulation.
/**
 * This implementation of a transient incompressible Navier Stokes solver uses
 * the non-dimensionalized formulation. The coupled momentum and
 * incompressibilty equations are decoupled using the split scheme described in
 * [1]. This leads to three solving steps.
 *
 * 1. An extrapolation step for all nonlinear terms which are treated
 *    explicitly. This step avoids a fully coupled nonlinear solve and only
 *    requires a solve of the mass matrix in velocity space \f$M_v^{-1}\f$. On
 *    the other hand this introduces a CFL stability condition on the maximum
 *    timestep.
 *
 * 2. A Poisson solve \f$S_p^{-1}\f$.
 *
 * 3. A Helmholtz like solve \f$(M_v - \partial t K_v)^{-1}\f$.
 *
 * The numerical solver setup for each step are as follows.
 *
 * \f$M_v^{-1}\f$ is solved using CG with Jacobi as preconditioner.
 *
 * \f$S_p^{-1}\f$ is solved using CG with AMG applied to the low order refined
 * (LOR) assembled pressure poisson matrix. To avoid assembling a matrix for
 * preconditioning, one can use p-MG as an alternative (NYI).
 *
 * \f$(M_v - \partial t K_v)^{-1}\f$ due to the CFL condition we expect the time
 * step to be small. Therefore this is solved using CG with Jacobi as
 * preconditioner. For large time steps a preconditioner like AMG or p-MG should
 * be used (NYI).
 *
 * Statements marked with NYI mean this feature is planned but Not Yet
 * Implemented.
 *
 * A detailed description is available in [1] section 4.2. The algorithm is
 * originated from [2].
 *
 * [1] Michael Franco, Jean-Sylvain Camier, Julian Andrej, Will Pazner (2020)
 * High-order matrix-free incompressible flow solvers with GPU acceleration and
 * low-order refined preconditioners (https://arxiv.org/abs/1910.03032)
 *
 * [2] A. G. Tomboulides, J. C. Y. Lee & S. A. Orszag (1997) Numerical
 * Simulation of Low Mach Number Reactive Flows
 */
class NavierSolver
{
public:
   /// Initialize data structures, set FE space order and kinematic viscosity.
   /**
    * The ParMesh @a mesh can be a linear or curved parallel mesh. The @a order
    * of the finite element spaces is this algorithm is of equal order
    * \f$(P_N)^d P_N\f$ for velocity and pressure respectively. This means the
    * pressure is in discretized in the same space (just scalar instead of a
    * vector space) as the velocity.
    *
    * Kinematic viscosity (dimensionless) is set using @a kin_vis and
    * automatically converted to the Reynolds number. If you want to set the
    * Reynolds number directly, you can provide the inverse.
    */
   NavierSolver(ParMesh *mesh, int order, double kin_vis);

   /// Initialize forms, solvers and preconditioners.
   void Setup(double dt);

   /// Compute solution at the next time step t+dt.
   void Step(double &time, double dt, int cur_step);

   /// Return a pointer to the current velocity ParGridFunction.
   ParGridFunction *GetCurrentVelocity() { return &un_gf; }

   /// Return a pointer to the current pressure ParGridFunction.
   ParGridFunction *GetCurrentPressure() { return &pn_gf; }

   /// Add a Dirichlet boundary condition to the velocity field.
   void AddVelDirichletBC(VectorCoefficient *coeff, Array<int> &attr);

   void AddVelDirichletBC(VecFuncT *f, Array<int> &attr);

   /// Add a Dirichlet boundary condition to the pressure field.
   void AddPresDirichletBC(Coefficient *coeff, Array<int> &attr);

   void AddPresDirichletBC(ScalarFuncT *f, Array<int> &attr);

   /// Add an accelaration term to the RHS of the equation.
   /**
    * The VecFuncT @a f is evaluated at the current time t and extrapolated
    * together with the nonlinear parts of the Navier Stokes equation.
    */
   void AddAccelTerm(VectorCoefficient *coeff, Array<int> &attr);

   void AddAccelTerm(VecFuncT *f, Array<int> &attr);

   /// Enable partial assembly for every operator.
   void EnablePA(bool pa) { partial_assembly = pa; }

   /// Enable numerical integration rules. This means collocated quadrature at
   /// the nodal points.
   void EnableNI(bool ni) { numerical_integ = ni; }

   /// Print timing summary of the solving routine.
   /**
    * The summary shows the timing in seconds in the first row of
    *
    * 1. SETUP: Time spent for the setup of all forms, solvers and
    *    preconditioners.
    * 2. STEP: Time spent computing a full time step. It includes allthree
    *    solves.
    * 3. EXTRAP: Time spent for extrapolation of all forcing and nonlinear
    *    terms.
    * 4. CURLCURL: Time spent for computing the curl curl term in the pressure
    *    Poisson equation (see references for detailed explanation).
    * 5. PSOLVE: Time spent in the pressure Poisson solve.
    * 6. HSOLVE: Time spent in the Helmholtz solve.
    *
    * The second row shows a proportion of a column relative to the whole
    * time step.
    */
   void PrintTimingData();

   ~NavierSolver();

   /// Compute \f$\nabla \times \nabla \times u\f$ for \f$u \in (H^1)^2\f$.
   void ComputeCurl2D(ParGridFunction &u,
                      ParGridFunction &cu,
                      bool assume_scalar = false);

   /// Compute \f$\nabla \times \nabla \times u\f$ for \f$u \in (H^1)^3\f$.
   void ComputeCurl3D(ParGridFunction &u, ParGridFunction &cu);

   /// Remove mean from a Vector.
   /**
    * Modify the Vector @a v by subtracting its mean using
    * \f$v = v - \frac{\sum_i^N v_i}{N} \f$
    */
   void Orthogonalize(Vector &v);

   /// Remove the mean from a ParGridFunction.
   /**
    * Modify the ParGridFunction @a v by subtracting its mean using
    * \f$ v = v - \int_\Omega \frac{v}{vol(\Omega)} dx \f$.
    */
   void MeanZero(ParGridFunction &v);

   /// Compute CFL
   double ComputeCFL(ParGridFunction &u, double dt);

   /// Set the number of modes to cut off in the interpolation filter
   void SetCutoffModes(int c) { filter_cutoff_modes = c; }

   /// Set the interpolation filter parameter @a alpha
   /**
    * If @a a is > 0, the filtering algorithm for the velocity field after every
    * time step from [1] is used.
    *
    * [1] Paul Fischer, Julia Mullen: Filter-based stabilization of spectral
    * element methods
    */
   void SetFilterAlpha(double a) { filter_alpha = a; }

protected:
   /// Print informations about the Navier version.
   void PrintInfo();

   /// Update the EXTk/BDF time integration coefficient.
   /**
    * Depending on which time step the computation is in, the EXTk/BDF time
    * integration coefficients have to be set accordingly. This allows
    * bootstrapping with a BDF scheme of order 1 and increasing the order each
    * following time step, up to order 3.
    */
   void SetTimeIntegrationCoefficients(int step);

   /// Eliminate essential BCs in an Operator and apply to RHS.
   void EliminateRHS(Operator &A,
                     ConstrainedOperator &constrainedA,
                     const Array<int> &ess_tdof_list,
                     Vector &x,
                     Vector &b,
                     Vector &X,
                     Vector &B,
                     int copy_interior = 0);

   /// Enable/disable debug output.
   bool debug = false;

   /// Enable/disable verbose output.
   bool verbose = true;

   /// Enable/disable partial assembly of forms.
   bool partial_assembly = false;

   /// Enable/disable numerical integration rules of forms.
   bool numerical_integ = false;

   /// The parallel mesh.
   ParMesh *pmesh = nullptr;

   /// The order of the velocity and pressure space.
   int order;

   /// Kinematic viscosity (dimensionless).
   double kin_vis;

   /// Velocity \f$H^1\f$ finite element collection.
   FiniteElementCollection *vfec = nullptr;

   /// Pressure \f$H^1\f$ finite element collection.
   FiniteElementCollection *pfec = nullptr;

   /// Velocity \f$(H^1)^d\f$ finite element space.
   ParFiniteElementSpace *vfes = nullptr;

   /// Pressure \f$H^1\f$ finite element space.
   ParFiniteElementSpace *pfes = nullptr;

   ParNonlinearForm *N = nullptr;

   ParBilinearForm *Mv_form = nullptr;

   ParBilinearForm *Sp_form = nullptr;

   ParMixedBilinearForm *D_form = nullptr;

   ParMixedBilinearForm *G_form = nullptr;

   ParBilinearForm *H_form = nullptr;

   VectorGridFunctionCoefficient *FText_gfcoeff = nullptr;

   ParLinearForm *FText_bdr_form = nullptr;

   ParLinearForm *f_form = nullptr;

   ParLinearForm *g_bdr_form = nullptr;

   /// Linear form to compute the mass matrix in various subroutines.
   ParLinearForm *mass_lf = nullptr;
   ConstantCoefficient onecoeff;
   double volume = 0.0;

   ConstantCoefficient nlcoeff;
   ConstantCoefficient Sp_coeff;
   ConstantCoefficient H_lincoeff;
   ConstantCoefficient H_bdfcoeff;

   OperatorHandle Mv;
   OperatorHandle Sp;
   OperatorHandle D;
   OperatorHandle G;
   OperatorHandle H;

   Solver *MvInvPC = nullptr;
   CGSolver *MvInv = nullptr;

   HypreBoomerAMG *SpInvPC = nullptr;
   OrthoSolver *SpInvOrthoPC = nullptr;
   CGSolver *SpInv = nullptr;

   Solver *HInvPC = nullptr;
   CGSolver *HInv = nullptr;

   Vector fn, un, unm1, unm2, Nun, Nunm1, Nunm2, Fext, FText, Lext, resu;
   Vector tmp1;

   Vector pn, resp, FText_bdr, g_bdr;

   ParGridFunction un_gf, curlu_gf, curlcurlu_gf, Lext_gf, FText_gf, resu_gf;

   ParGridFunction pn_gf, resp_gf;

   // All essential attributes.
   Array<int> vel_ess_attr;
   Array<int> pres_ess_attr;

   // All essential true dofs.
   Array<int> vel_ess_tdof;
   Array<int> pres_ess_tdof;

   // Bookkeeping for velocity dirichlet bcs.
   std::vector<VelDirichletBC_T> vel_dbcs;

   // Bookkeeping for pressure dirichlet bcs.
   std::vector<PresDirichletBC_T> pres_dbcs;

   // Bookkeeping for acceleration (forcing) terms.
   std::vector<AccelTerm_T> accel_terms;

   int cur_step = 0;

   // BDFk/EXTk coefficients.
   double bd0 = 0.0;
   double bd1 = 0.0;
   double bd2 = 0.0;
   double bd3 = 0.0;
   double ab1 = 0.0;
   double ab2 = 0.0;
   double ab3 = 0.0;

   // Timers.
   StopWatch sw_setup, sw_step, sw_extrap, sw_curlcurl, sw_spsolve, sw_hsolve;

   // Print levels.
   int pl_mvsolve = 0;
   int pl_spsolve = 0;
   int pl_hsolve = 0;
   int pl_amg = 0;

   // Relative tolerances.
   double rtol_spsolve = 1e-6;
   double rtol_hsolve = 1e-8;

   // Iteration counts.
   int iter_mvsolve = 0, iter_spsolve = 0, iter_hsolve = 0;

   // Residuals.
   double res_mvsolve = 0.0, res_spsolve = 0.0, res_hsolve = 0.0;

   // LOR related.
   ParMesh *pmesh_lor = nullptr;
   FiniteElementCollection *pfec_lor = nullptr;
   ParFiniteElementSpace *pfes_lor = nullptr;
   InterpolationGridTransfer *vgt = nullptr, *pgt = nullptr;

   ParBilinearForm *Mv_form_lor = nullptr;
   ParBilinearForm *Sp_form_lor = nullptr;
   ParBilinearForm *H_form_lor = nullptr;

   OperatorHandle Mv_lor;
   OperatorHandle Sp_lor;
   OperatorHandle H_lor;

   // Filter-based stabilization
   int filter_cutoff_modes = 1;
   double filter_alpha = 0.0;
   FiniteElementCollection *vfec_filter = nullptr;
   ParFiniteElementSpace *vfes_filter = nullptr;
   ParGridFunction un_NM1_gf;
   ParGridFunction un_filtered_gf;
};
} // namespace navier
} // namespace mfem
#endif
<|endoftext|>


<commit_before>// This file is part of the dune-gdt project:
//   https://github.com/dune-community/dune-gdt
// Copyright 2010-2017 dune-gdt developers and contributors. All rights reserved.
// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//      or  GPL-2.0+ (http://opensource.org/licenses/gpl-license)
//          with "runtime exception" (http://www.dune-project.org/license.html)
// Authors:
//   Felix Schindler (2015 - 2017)
//   Rene Milk       (2016 - 2017)

#include <dune/xt/common/test/main.hxx> // <- this one has to come first

#include "l2.hh"
#include <dune/gdt/test/spaces/cg/pdelab.hh>
#include <dune/gdt/test/spaces/dg/fem.hh>
#include <dune/gdt/test/spaces/fv/default.hh>

using namespace Dune::GDT::Test;

#if HAVE_DUNE_FEM

typedef testing::Types<SPACE_DG_FEM_YASPGRID(1, 1, 2), SPACE_DG_FEM_YASPGRID(2, 1, 2), SPACE_DG_FEM_YASPGRID(3, 1, 2)>
    QuadraticSpaces;
TYPED_TEST_CASE(L2MatrixOperatorTest, QuadraticSpaces);

#elif HAVE_DUNE_PDELAB // HAVE_DUNE_FEM

typedef testing::Types<SPACE_CG_PDELAB_YASPGRID(1, 1, 1),
                       SPACE_CG_PDELAB_YASPGRID(2, 1, 1),
                       SPACE_CG_PDELAB_YASPGRID(3, 1, 1)>
    LinearSpaces;
TYPED_TEST_CASE(L2MatrixOperatorTest, LinearSpaces);

#else // HAVE_DUNE_FEM || HAVE_DUNE_PDELAB

typedef testing::Types<SPACE_FV_YASPGRID(1, 1), SPACE_FV_YASPGRID(2, 1), SPACE_FV_YASPGRID(3, 1)> ConstantSpaces;
TYPED_TEST_CASE(L2MatrixOperatorTest, ConstantSpaces);

#endif // HAVE_DUNE_FEM || HAVE_DUNE_PDELAB

TYPED_TEST(L2MatrixOperatorTest, constructible_by_ctor)
{
  this->constructible_by_ctor();
}
TYPED_TEST(L2MatrixOperatorTest, constructible_by_factory)
{
  this->constructible_by_factory();
}
TYPED_TEST(L2MatrixOperatorTest, is_matrix_operator)
{
  this->is_matrix_operator();
}
TYPED_TEST(L2MatrixOperatorTest, correct_for_constant_arguments)
{
  this->correct_for_constant_arguments(2.5e-15);
}

#if HAVE_DUNE_FEM || HAVE_DUNE_PDELAB
TYPED_TEST(L2MatrixOperatorTest, correct_for_linear_arguments)
{
  this->correct_for_linear_arguments();
}
#else
TEST(DISABLED_L2MatrixOperatorTest, correct_for_linear_arguments)
{
  std::cerr << Dune::XT::Common::colorStringRed("Missing dependencies!") << std::endl;
}
#endif

#if HAVE_DUNE_FEM
TYPED_TEST(L2MatrixOperatorTest, correct_for_quadratic_arguments)
{
  this->correct_for_quadratic_arguments();
}
#else
TEST(DISABLED_L2MatrixOperatorTest, correct_for_quadratic_arguments)
{
  std::cerr << Dune::XT::Common::colorStringRed("Missing dependencies!") << std::endl;
}
#endif
<commit_msg>[test] lower expectations for l2 matrix operator<commit_after>// This file is part of the dune-gdt project:
//   https://github.com/dune-community/dune-gdt
// Copyright 2010-2017 dune-gdt developers and contributors. All rights reserved.
// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//      or  GPL-2.0+ (http://opensource.org/licenses/gpl-license)
//          with "runtime exception" (http://www.dune-project.org/license.html)
// Authors:
//   Felix Schindler (2015 - 2017)
//   Rene Milk       (2016 - 2017)

#include <dune/xt/common/test/main.hxx> // <- this one has to come first

#include "l2.hh"
#include <dune/gdt/test/spaces/cg/pdelab.hh>
#include <dune/gdt/test/spaces/dg/fem.hh>
#include <dune/gdt/test/spaces/fv/default.hh>

using namespace Dune::GDT::Test;

#if HAVE_DUNE_FEM

typedef testing::Types<SPACE_DG_FEM_YASPGRID(1, 1, 2), SPACE_DG_FEM_YASPGRID(2, 1, 2), SPACE_DG_FEM_YASPGRID(3, 1, 2)>
    QuadraticSpaces;
TYPED_TEST_CASE(L2MatrixOperatorTest, QuadraticSpaces);

#elif HAVE_DUNE_PDELAB // HAVE_DUNE_FEM

typedef testing::Types<SPACE_CG_PDELAB_YASPGRID(1, 1, 1),
                       SPACE_CG_PDELAB_YASPGRID(2, 1, 1),
                       SPACE_CG_PDELAB_YASPGRID(3, 1, 1)>
    LinearSpaces;
TYPED_TEST_CASE(L2MatrixOperatorTest, LinearSpaces);

#else // HAVE_DUNE_FEM || HAVE_DUNE_PDELAB

typedef testing::Types<SPACE_FV_YASPGRID(1, 1), SPACE_FV_YASPGRID(2, 1), SPACE_FV_YASPGRID(3, 1)> ConstantSpaces;
TYPED_TEST_CASE(L2MatrixOperatorTest, ConstantSpaces);

#endif // HAVE_DUNE_FEM || HAVE_DUNE_PDELAB

TYPED_TEST(L2MatrixOperatorTest, constructible_by_ctor)
{
  this->constructible_by_ctor();
}
TYPED_TEST(L2MatrixOperatorTest, constructible_by_factory)
{
  this->constructible_by_factory();
}
TYPED_TEST(L2MatrixOperatorTest, is_matrix_operator)
{
  this->is_matrix_operator();
}
TYPED_TEST(L2MatrixOperatorTest, correct_for_constant_arguments)
{
  this->correct_for_constant_arguments(1.5e-14);
}

#if HAVE_DUNE_FEM || HAVE_DUNE_PDELAB
TYPED_TEST(L2MatrixOperatorTest, correct_for_linear_arguments)
{
  this->correct_for_linear_arguments();
}
#else
TEST(DISABLED_L2MatrixOperatorTest, correct_for_linear_arguments)
{
  std::cerr << Dune::XT::Common::colorStringRed("Missing dependencies!") << std::endl;
}
#endif

#if HAVE_DUNE_FEM
TYPED_TEST(L2MatrixOperatorTest, correct_for_quadratic_arguments)
{
  this->correct_for_quadratic_arguments();
}
#else
TEST(DISABLED_L2MatrixOperatorTest, correct_for_quadratic_arguments)
{
  std::cerr << Dune::XT::Common::colorStringRed("Missing dependencies!") << std::endl;
}
#endif
<|endoftext|>


<commit_before>/**
 * @file density.cpp
 *
 * Computes desity for dry air from pressure and temperature using the ideal gas law.
 *
 * @date Mar 11, 2014
 * @author Tack
 */

#include "density.h"
#include "plugin_factory.h"
#include "logger_factory.h"
#include <boost/lexical_cast.hpp>
#include <boost/thread.hpp>

#define HIMAN_AUXILIARY_INCLUDE

#include "fetcher.h"

#undef HIMAN_AUXILIARY_INCLUDE

using namespace std;
using namespace himan::plugin;

const string itsName("density");

density::density()
{
	itsLogger = unique_ptr<logger> (logger_factory::Instance()->GetLog(itsName));

}

void density::Process(std::shared_ptr<const plugin_configuration> conf)
{
	Init(conf);

	/*
	 * Set target parameter to ???
	 * - name PARM_NAME
	 * - univ_id UNIV_ID
	 * - grib2 descriptor X'Y'Z
	 *
	 * We need to specify grib and querydata parameter information
	 * since we don't know which one will be the output format.
	 *
	 */

	vector<param> theParams;

	param theRequestedParam("RHO-KGM3", 9999);

	// GRIB 2

	theRequestedParam.GribDiscipline(0);
	theRequestedParam.GribCategory(3);
	theRequestedParam.GribParameter(10);

	// GRIB 1

	/*
	 * GRIB 1 parameters go here
	 *
	 */

	theParams.push_back(theRequestedParam);

	SetParams(theParams);

	Start();
}

/*
 * Calculate()
 *
 * This function does the actual calculation.
 */

void density::Calculate(shared_ptr<info> myTargetInfo, unsigned short threadIndex)
{

	shared_ptr<fetcher> theFetcher = dynamic_pointer_cast <fetcher> (plugin_factory::Instance()->Plugin("fetcher"));

	// Required source parameters

	/*
	 * eg. param PParam("P-Pa"); for pressure in pascals
	 *
	 */

	param PParam("P-PA");
	param TParam("T-K");
	// ----

	unique_ptr<logger> myThreadedLogger = std::unique_ptr<logger> (logger_factory::Instance()->GetLog(itsName + "Thread #" + boost::lexical_cast<string> (threadIndex)));

	ResetNonLeadingDimension(myTargetInfo);

	myTargetInfo->FirstParam();

	while (AdjustNonLeadingDimension(myTargetInfo))
	{
		myThreadedLogger->Debug("Calculating time " + myTargetInfo->Time().ValidDateTime()->String("%Y%m%d%H") +
								" level " + boost::lexical_cast<string> (myTargetInfo->Level().Value()));

		shared_ptr<info> PInfo;
		shared_ptr<info> TInfo;
		try
		{
			// Source info for PParam and TParam
			PInfo = theFetcher->Fetch(itsConfiguration,
							myTargetInfo->Time(),
							myTargetInfo->Level(),
							PParam);
			TInfo = theFetcher->Fetch(itsConfiguration,
							myTargetInfo->Time(),
							myTargetInfo->Level(),
							TParam);

			// ----
		}
		catch (HPExceptionType e)
		{
			switch (e)
			{
				case kFileDataNotFound:
					itsLogger->Warning("Skipping step " + boost::lexical_cast<string> (myTargetInfo->Time().Step()) + ", level " + boost::lexical_cast<string> (myTargetInfo->Level().Value()));
					myTargetInfo->Data()->Fill(kFloatMissing);

					if (itsConfiguration->StatisticsEnabled())
					{
						itsConfiguration->Statistics()->AddToMissingCount(myTargetInfo->Grid()->Size());
						itsConfiguration->Statistics()->AddToValueCount(myTargetInfo->Grid()->Size());
					}

					continue;
					break;

				default:
					throw runtime_error(ClassName() + ": Unable to proceed");
					break;
			}
		}

		unique_ptr<timer> processTimer = unique_ptr<timer> (timer_factory::Instance()->GetTimer());

		if (itsConfiguration->StatisticsEnabled())
		{
			processTimer->Start();
		}

		int missingCount = 0;
		int count = 0;

		/*
		 * Converting original grid-data to newbase grid
		 *
		 */

		shared_ptr<NFmiGrid> targetGrid(myTargetInfo->Grid()->ToNewbaseGrid());
		shared_ptr<NFmiGrid> PGrid(PInfo->Grid()->ToNewbaseGrid());
		shared_ptr<NFmiGrid> TGrid(TInfo->Grid()->ToNewbaseGrid());

		bool equalGrids = (*myTargetInfo->Grid() == *PInfo->Grid() && *myTargetInfo->Grid() == *TInfo->Grid());

		string deviceType;

		{

			deviceType = "CPU";

			assert(targetGrid->Size() == myTargetInfo->Data()->Size());

			myTargetInfo->ResetLocation();

			targetGrid->Reset();

			while (myTargetInfo->NextLocation() && targetGrid->Next())
			{

				count++;

				/*
				 * interpolation happens here
				 *
				 */
				double P = kFloatMissing;
				double T = kFloatMissing;

				InterpolateToPoint(targetGrid, PGrid, equalGrids, P);
				InterpolateToPoint(targetGrid, TGrid, equalGrids, T);

				if (P == kFloatMissing || T == kFloatMissing )
				{
					missingCount++;

					myTargetInfo->Value(kFloatMissing);
					continue;
				}

				// actual calculation of the density using the ideal gas law
				double rho;

				rho = P / (constants::kRd * T);

				if (!myTargetInfo->Value(rho))
				{
					throw runtime_error(ClassName() + ": Failed to set value to matrix");
				}
			}

		}

		/*
		 * Newbase normalizes scanning mode to bottom left -- if that's not what
		 * the target scanning mode is, we have to swap the data back.
		 */

		SwapTo(myTargetInfo, kBottomLeft);

		if (itsConfiguration->StatisticsEnabled())
		{
			processTimer->Stop();
			itsConfiguration->Statistics()->AddToProcessingTime(processTimer->GetTime());

#ifdef DEBUG
			itsLogger->Debug("Calculation took " + boost::lexical_cast<string> (processTimer->GetTime()) + " microseconds on "  + deviceType);
#endif

			itsConfiguration->Statistics()->AddToMissingCount(missingCount);
			itsConfiguration->Statistics()->AddToValueCount(count);

		}

		/*
		 * Now we are done for this level
		 *
		 * Clone info-instance to writer since it might change our descriptor places
		 * */

		myThreadedLogger->Info("Missing values: " + boost::lexical_cast<string> (missingCount) + "/" + boost::lexical_cast<string> (count));

		if (itsConfiguration->FileWriteOption() != kSingleFile)
		{
			WriteToFile(myTargetInfo);
		}
	}
}
<commit_msg>Changed PParam to also except pressure in hPa and made changes to allow calculation on pressure levels.<commit_after>/**
 * @file density.cpp
 *
 * Computes desity for dry air from pressure and temperature using the ideal gas law.
 *
 * @date Mar 11, 2014
 * @author Tack
 */

#include "density.h"
#include "plugin_factory.h"
#include "logger_factory.h"
#include <boost/lexical_cast.hpp>
#include <boost/thread.hpp>

#define HIMAN_AUXILIARY_INCLUDE

#include "fetcher.h"

#undef HIMAN_AUXILIARY_INCLUDE

using namespace std;
using namespace himan::plugin;

const string itsName("density");

density::density()
{
	itsLogger = unique_ptr<logger> (logger_factory::Instance()->GetLog(itsName));

}

void density::Process(std::shared_ptr<const plugin_configuration> conf)
{
	Init(conf);

	/*
	 * Set target parameter to ???
	 * - name PARM_NAME
	 * - univ_id UNIV_ID
	 * - grib2 descriptor X'Y'Z
	 *
	 * We need to specify grib and querydata parameter information
	 * since we don't know which one will be the output format.
	 *
	 */

	vector<param> theParams;

	param theRequestedParam("RHO-KGM3", 9999);

	// GRIB 2

	theRequestedParam.GribDiscipline(0);
	theRequestedParam.GribCategory(3);
	theRequestedParam.GribParameter(10);

	// GRIB 1

	/*
	 * GRIB 1 parameters go here
	 *
	 */

	theParams.push_back(theRequestedParam);

	SetParams(theParams);

	Start();
}

/*
 * Calculate()
 *
 * This function does the actual calculation.
 */

void density::Calculate(shared_ptr<info> myTargetInfo, unsigned short threadIndex)
{

	shared_ptr<fetcher> theFetcher = dynamic_pointer_cast <fetcher> (plugin_factory::Instance()->Plugin("fetcher"));

	// Required source parameters

	/*
	 * eg. param PParam("P-Pa"); for pressure in pascals
	 *
	 */

	params PParam = { param("P-PA"), param("P-HPA") };
	param TParam("T-K");
	// ----

	unique_ptr<logger> myThreadedLogger = std::unique_ptr<logger> (logger_factory::Instance()->GetLog(itsName + "Thread #" + boost::lexical_cast<string> (threadIndex)));

	ResetNonLeadingDimension(myTargetInfo);

	myTargetInfo->FirstParam();

	while (AdjustNonLeadingDimension(myTargetInfo))
	{
		myThreadedLogger->Debug("Calculating time " + myTargetInfo->Time().ValidDateTime()->String("%Y%m%d%H") +
								" level " + boost::lexical_cast<string> (myTargetInfo->Level().Value()));
		double PScale = 1;

		shared_ptr<info> PInfo;
		shared_ptr<info> TInfo;

		shared_ptr<NFmiGrid> PGrid;
		bool isPressureLevel = (myTargetInfo->Level().Type() == kPressure);

		try
		{
			if(!isPressureLevel)
			{
			// Source info for PParam and TParam
				PInfo = theFetcher->Fetch(itsConfiguration,
								myTargetInfo->Time(),
								myTargetInfo->Level(),
								PParam);

				if (PInfo->Param().Unit() == kHPa || PInfo->Param().Name() == "P-HPA")
				{
					PScale = 100;
				}

				PGrid = shared_ptr<NFmiGrid> (PInfo->Grid()->ToNewbaseGrid());
			}
			TInfo = theFetcher->Fetch(itsConfiguration,
							myTargetInfo->Time(),
							myTargetInfo->Level(),
							TParam);

			// ----
		}
		catch (HPExceptionType e)
		{
			switch (e)
			{
				case kFileDataNotFound:
					itsLogger->Warning("Skipping step " + boost::lexical_cast<string> (myTargetInfo->Time().Step()) + ", level " + boost::lexical_cast<string> (myTargetInfo->Level().Value()));
					myTargetInfo->Data()->Fill(kFloatMissing);

					if (itsConfiguration->StatisticsEnabled())
					{
						itsConfiguration->Statistics()->AddToMissingCount(myTargetInfo->Grid()->Size());
						itsConfiguration->Statistics()->AddToValueCount(myTargetInfo->Grid()->Size());
					}

					continue;
					break;

				default:
					throw runtime_error(ClassName() + ": Unable to proceed");
					break;
			}
		}

		unique_ptr<timer> processTimer = unique_ptr<timer> (timer_factory::Instance()->GetTimer());

		if (itsConfiguration->StatisticsEnabled())
		{
			processTimer->Start();
		}

		int missingCount = 0;
		int count = 0;

		/*
		 * Converting original grid-data to newbase grid
		 *
		 */

		shared_ptr<NFmiGrid> targetGrid(myTargetInfo->Grid()->ToNewbaseGrid());
		shared_ptr<NFmiGrid> TGrid(TInfo->Grid()->ToNewbaseGrid());

		bool equalGrids = ((isPressureLevel || *myTargetInfo->Grid() == *PInfo->Grid()) && *myTargetInfo->Grid() == *TInfo->Grid());

		string deviceType;

		{

			deviceType = "CPU";

			assert(targetGrid->Size() == myTargetInfo->Data()->Size());

			myTargetInfo->ResetLocation();

			targetGrid->Reset();

			while (myTargetInfo->NextLocation() && targetGrid->Next())
			{

				count++;

				/*
				 * interpolation happens here
				 *
				 */
				double P = kFloatMissing;
				double T = kFloatMissing;

				if (isPressureLevel)
				{
					P = 100 * myTargetInfo->Level().Value();
				}
				else
				{
				 	InterpolateToPoint(targetGrid, PGrid, equalGrids, P);
				}

				InterpolateToPoint(targetGrid, TGrid, equalGrids, T);

				if (P == kFloatMissing || T == kFloatMissing )
				{
					missingCount++;

					myTargetInfo->Value(kFloatMissing);
					continue;
				}

				// actual calculation of the density using the ideal gas law
				double rho;

				rho = P * PScale / (constants::kRd * T);

				if (!myTargetInfo->Value(rho))
				{
					throw runtime_error(ClassName() + ": Failed to set value to matrix");
				}
			}

		}

		/*
		 * Newbase normalizes scanning mode to bottom left -- if that's not what
		 * the target scanning mode is, we have to swap the data back.
		 */

		SwapTo(myTargetInfo, kBottomLeft);

		if (itsConfiguration->StatisticsEnabled())
		{
			processTimer->Stop();
			itsConfiguration->Statistics()->AddToProcessingTime(processTimer->GetTime());

#ifdef DEBUG
			itsLogger->Debug("Calculation took " + boost::lexical_cast<string> (processTimer->GetTime()) + " microseconds on "  + deviceType);
#endif

			itsConfiguration->Statistics()->AddToMissingCount(missingCount);
			itsConfiguration->Statistics()->AddToValueCount(count);

		}

		/*
		 * Now we are done for this level
		 *
		 * Clone info-instance to writer since it might change our descriptor places
		 * */

		myThreadedLogger->Info("Missing values: " + boost::lexical_cast<string> (missingCount) + "/" + boost::lexical_cast<string> (count));

		if (itsConfiguration->FileWriteOption() != kSingleFile)
		{
			WriteToFile(myTargetInfo);
		}
	}
}
<|endoftext|>