<commit_before>////////////////////////////////////////////////////////////////////////////////
/// @brief infrastructure for query optimizer
///
/// @file arangod/Aql/Optimizer.cpp
///
/// DISCLAIMER
///
/// Copyright 2010-2014 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Max Neunhoeffer
/// @author Copyright 2014, triagens GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "Aql/Optimizer.h"
#include "Aql/ExecutionEngine.h"
#include "Aql/OptimizerRules.h"
#include "Cluster/ServerState.h"

using namespace triagens::aql;

// -----------------------------------------------------------------------------
// --SECTION--                                               the optimizer class
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------
// --SECTION--                                            static initializations
// -----------------------------------------------------------------------------

triagens::basics::Mutex Optimizer::SetupLock;

////////////////////////////////////////////////////////////////////////////////
// @brief list of all rules
////////////////////////////////////////////////////////////////////////////////

std::map<int, Optimizer::Rule> Optimizer::_rules;

////////////////////////////////////////////////////////////////////////////////
// @brief lookup from rule name to rule level
////////////////////////////////////////////////////////////////////////////////

std::unordered_map<std::string, int> Optimizer::_ruleLookup;

// -----------------------------------------------------------------------------
// --SECTION--                                        constructors / destructors
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
// @brief constructor, this will initialize the rules database
////////////////////////////////////////////////////////////////////////////////

Optimizer::Optimizer (size_t maxNumberOfPlans)
  : _maxNumberOfPlans(maxNumberOfPlans > 0 ? maxNumberOfPlans : DefaultMaxNumberOfPlans) {

  if (_rules.empty()) {
    setupRules();
  }
}

// -----------------------------------------------------------------------------
// --SECTION--                                                    public methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
// @brief add a plan to the optimizer
////////////////////////////////////////////////////////////////////////////////

bool Optimizer::addPlan (ExecutionPlan* plan,
                         RuleLevel level,
                         bool wasModified) {
  TRI_ASSERT(plan != nullptr);

  _newPlans.push_back(plan, level);

  if (wasModified) {
    // register which rules modified / created the plan
    plan->addAppliedRule(_currentRule);
    plan->invalidateCost();
  }

  if (_newPlans.size() >= _maxNumberOfPlans) {
    return false;
  }

  return true;
}

////////////////////////////////////////////////////////////////////////////////
// @brief the actual optimization
////////////////////////////////////////////////////////////////////////////////

int Optimizer::createPlans (ExecutionPlan* plan,
                            std::vector<std::string> const& rulesSpecification,
                            bool inspectSimplePlans) {
  if (! inspectSimplePlans &&
      ! ExecutionEngine::isCoordinator() &&
      plan->isDeadSimple()) {
    // the plan is so simple that any further optimizations would probably cost
    // more than simply executing the plan
    _plans.clear();
    _plans.push_back(plan, 0);
    estimatePlans();

    return TRI_ERROR_NO_ERROR;
  }

  bool runOnlyRequiredRules = false;
  int leastDoneLevel = 0;

  TRI_ASSERT(! _rules.empty());
  int maxRuleLevel = _rules.rbegin()->first;

  // which optimizer rules are disabled?
  std::unordered_set<int> const&& disabledIds = getDisabledRuleIds(rulesSpecification);

  // _plans contains the previous optimisation result
  _plans.clear();
  _plans.push_back(plan, 0);

  _newPlans.clear();

  while (leastDoneLevel < maxRuleLevel) {
    // Find variable usage for all old plans now:
    for (auto p : _plans.list) {
      if (! p->varUsageComputed()) {
        p->findVarUsage();
      }
    }

    // std::cout << "Have " << _plans.size() << " plans:" << std::endl;
    /*
    for (auto p : _plans.list) {
      p->show();
      std::cout << std::endl;
    }
    */

    // int count = 0;

    // For all current plans:
    while (_plans.size() > 0) {
      int level;
      auto p = _plans.pop_front(level);

      if (level >= maxRuleLevel) {
        _newPlans.push_back(p, level);  // nothing to do, just keep it
      }
      else {   // find next rule
        auto it = _rules.upper_bound(level);
        TRI_ASSERT(it != _rules.end());

        /*
        std::cout << "Trying rule " << it->second.name << " with level "
                  << it->first << " on plan " << count++
                  << std::endl;
        */

        level = (*it).first;
        if ((runOnlyRequiredRules || disabledIds.find(level) != disabledIds.end()) &&
            (*it).second.canBeDisabled) {
          // we picked a disabled rule or we have reached the max number of plans
          // and just skip this rule
          level = it->first;

          _newPlans.push_back(p, level);  // nothing to do, just keep it
          // now try next
          continue;
        }

        _currentRule = level;

        int res;
        try {
          res = (*it).second.func(this, p, &(it->second));
        }
        catch (...) {
          delete p;
          throw;
        }

        if (res != TRI_ERROR_NO_ERROR) {
          return res;
        }
      }

      // TODO: abort early here if we found a good-enough plan
      // a good-enough plan is probably every plan with costs below some
      // defined threshold. this requires plan costs to be calculated here
    }

    _plans.steal(_newPlans);
    leastDoneLevel = maxRuleLevel;
    for (auto l : _plans.levelDone) {
      if (l < leastDoneLevel) {
        leastDoneLevel = l;
      }
    }
    // std::cout << "Least done level is " << leastDoneLevel << std::endl;

    // Stop if the result gets out of hand:
    if (! runOnlyRequiredRules &&
        _plans.size() >= _maxNumberOfPlans) {
      // must still iterate over all REQUIRED remaining transformation rules
      // because there are some rules which are required to make the query
      // work in cluster mode
      runOnlyRequiredRules = true;
    }
  }

  TRI_ASSERT(_plans.size() >= 1);

  estimatePlans();
  sortPlans();
  /*
  std::cout << "Optimisation ends with " << _plans.size() << " plans."
            << std::endl;
  for (auto p : _plans.list) {
    p->show();
    std::cout << "costing: " << p->getCost() << std::endl;
    std::cout << std::endl;
  }
  */

  return TRI_ERROR_NO_ERROR;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief translate a list of rule ids into rule name
////////////////////////////////////////////////////////////////////////////////

std::vector<std::string> Optimizer::translateRules (std::vector<int> const& rules) {
  std::vector<std::string> names;

  for (auto r : rules) {
    auto it = _rules.find(r);
    if (it != _rules.end()) {
      names.emplace_back((*it).second.name);
    }
  }
  return names;
}

// -----------------------------------------------------------------------------
// --SECTION--                                                   private methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief estimatePlans
////////////////////////////////////////////////////////////////////////////////

void Optimizer::estimatePlans () {
  for (auto p : _plans.list) {
    p->getCost();
    // this value is cached in the plan, so formally this step is
    // unnecessary, but for the sake of cleanliness...
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief sortPlans
////////////////////////////////////////////////////////////////////////////////

void Optimizer::sortPlans () {
  std::sort(_plans.list.begin(), _plans.list.end(), [](ExecutionPlan* const& a, ExecutionPlan* const& b) -> bool {
    return a->getCost() < b->getCost();
  });
}

////////////////////////////////////////////////////////////////////////////////
/// @brief look up the ids of all disabled rules
////////////////////////////////////////////////////////////////////////////////

std::unordered_set<int> Optimizer::getDisabledRuleIds (std::vector<std::string> const& names) const {
  std::unordered_set<int> disabled;

  // lookup ids of all disabled rules
  for (auto name : names) {
    if (name[0] == '-') {
      // disable rule
      if (name == "-all") {
        // disable all rules
        for (auto it : _rules) {
          disabled.insert(it.first);
        }
      }
      else {
        // disable a specific rule
        auto it = _ruleLookup.find(std::string(name.c_str() + 1));
        if (it != _ruleLookup.end()) {
          disabled.insert((*it).second);
        }
      }
    }
    else if (name[0] == '+') {
      // enable rule
      if (name == "+all") {
        // enable all rules
        disabled.clear();
      }
      else {
        auto it = _ruleLookup.find(std::string(name.c_str() + 1));
        if (it != _ruleLookup.end()) {
          disabled.erase((*it).second);
        }
      }
    }
  }

  return disabled;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief set up the optimizer rules once and forever
////////////////////////////////////////////////////////////////////////////////

void Optimizer::setupRules () {
  MUTEX_LOCKER(SetupLock);

  if (! _rules.empty()) {
    // race condition... prevent duplicate registration of rules
    return;
  }

  // List all the rules in the system here:
  // lower level values mean earlier rule execution

  // note that levels must be unique

  //////////////////////////////////////////////////////////////////////////////
  // "Pass 1": moving nodes "up" (potentially outside loops):
  //           please use levels between 1 and 99 here
  //////////////////////////////////////////////////////////////////////////////

  // move calculations up the dependency chain (to pull them out of
  // inner loops etc.)
  registerRule("move-calculations-up",
               moveCalculationsUpRule,
               moveCalculationsUpRule_pass1,
               true);

  // move filters up the dependency chain (to make result sets as small
  // as possible as early as possible)
  registerRule("move-filters-up",
               moveFiltersUpRule,
               moveFiltersUpRule_pass1,
               true);

  // remove redundant calculations
  registerRule("remove-redundant-calculations",
               removeRedundantCalculationsRule,
               removeRedundantCalculationsRule_pass1,
               true);

  //////////////////////////////////////////////////////////////////////////////
  /// "Pass 2": try to remove redundant or unnecessary nodes
  ///           use levels between 101 and 199 for this
  //////////////////////////////////////////////////////////////////////////////

  // remove filters from the query that are not necessary at all
  // filters that are always true will be removed entirely
  // filters that are always false will be replaced with a NoResults node
  registerRule("remove-unnecessary-filters",
               removeUnnecessaryFiltersRule,
               removeUnnecessaryFiltersRule_pass2,
               true);

  // remove calculations that are never necessary
  registerRule("remove-unnecessary-calculations",
               removeUnnecessaryCalculationsRule,
               removeUnnecessaryCalculationsRule_pass2,
               true);

  // remove redundant sort blocks
  registerRule("remove-redundant-sorts",
               removeRedundantSorts,
               removeRedundantSorts_pass2,
               true);

  //////////////////////////////////////////////////////////////////////////////
  /// "Pass 3": interchange EnumerateCollection nodes in all possible ways
  ///           this is level 500, please never let new plans from higher
  ///           levels go back to this or lower levels!
  //////////////////////////////////////////////////////////////////////////////

  registerRule("interchange-adjacent-enumerations",
               interchangeAdjacentEnumerations,
               interchangeAdjacentEnumerations_pass3,
               true);

  //////////////////////////////////////////////////////////////////////////////
  // "Pass 4": moving nodes "up" (potentially outside loops) (second try):
  //           please use levels between 501 and 599 here
  //////////////////////////////////////////////////////////////////////////////

  // move calculations up the dependency chain (to pull them out of
  // inner loops etc.)
  registerRule("move-calculations-up-2",
               moveCalculationsUpRule,
               moveCalculationsUpRule_pass4,
               true);

  // move filters up the dependency chain (to make result sets as small
  // as possible as early as possible)
  registerRule("move-filters-up-2",
               moveFiltersUpRule,
               moveFiltersUpRule_pass4,
               true);

  //////////////////////////////////////////////////////////////////////////////
  /// "Pass 5": try to remove redundant or unnecessary nodes (second try)
  ///           use levels between 601 and 699 for this
  //////////////////////////////////////////////////////////////////////////////

  // remove filters from the query that are not necessary at all
  // filters that are always true will be removed entirely
  // filters that are always false will be replaced with a NoResults node
  registerRule("remove-unnecessary-filters-2",
               removeUnnecessaryFiltersRule,
               removeUnnecessaryFiltersRule_pass5,
               true);

  // remove calculations that are never necessary
  registerRule("remove-unnecessary-calculations-2",
               removeUnnecessaryCalculationsRule,
               removeUnnecessaryCalculationsRule_pass5,
               true);

  // remove redundant sort blocks
  registerRule("remove-redundant-sorts-2",
               removeRedundantSorts,
               removeRedundantSorts_pass5,
               true);

  //////////////////////////////////////////////////////////////////////////////
  /// "Pass 6": use indexes if possible for FILTER and/or SORT nodes
  ///           use levels between 701 and 799 for this
  //////////////////////////////////////////////////////////////////////////////

  // try to find a filter after an enumerate collection and find an index . . .
  registerRule("use-index-range",
               useIndexRange,
               useIndexRange_pass6,
               true);

  // try to find sort blocks which are superseeded by indexes
  registerRule("use-index-for-sort",
               useIndexForSort,
               useIndexForSort_pass6,
               true);

  if (ExecutionEngine::isCoordinator()) {
    // distribute operations in cluster
    registerRule("scatter-in-cluster",
                 scatterInCluster,
                 scatterInCluster_pass10,
                 false);

    registerRule("distribute-in-cluster",
                 distributeInCluster,
                 distributeInCluster_pass10,
                 false);

    // distribute operations in cluster
    registerRule("distribute-filtercalc-to-cluster",
                 distributeFilternCalcToCluster,
                 distributeFilternCalcToCluster_pass10,
                 true);

    registerRule("distribute-sort-to-cluster",
                 distributeSortToCluster,
                 distributeSortToCluster_pass10,
                 true);

    registerRule("remove-unnecessary-remote-scatter",
                 removeUnnecessaryRemoteScatter,
                 removeUnnecessaryRemoteScatter_pass10,
                 true);

    registerRule("undistribute-remove-after-enum-coll",
                 undistributeRemoveAfterEnumColl,
                 undistributeRemoveAfterEnumColl_pass10,
                 true);

  }
}

// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)"
// End:

<commit_msg>Take out some debugging output.<commit_after>////////////////////////////////////////////////////////////////////////////////
/// @brief infrastructure for query optimizer
///
/// @file arangod/Aql/Optimizer.cpp
///
/// DISCLAIMER
///
/// Copyright 2010-2014 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Max Neunhoeffer
/// @author Copyright 2014, triagens GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "Aql/Optimizer.h"
#include "Aql/ExecutionEngine.h"
#include "Aql/OptimizerRules.h"
#include "Cluster/ServerState.h"

using namespace triagens::aql;

// -----------------------------------------------------------------------------
// --SECTION--                                               the optimizer class
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------
// --SECTION--                                            static initializations
// -----------------------------------------------------------------------------

triagens::basics::Mutex Optimizer::SetupLock;

////////////////////////////////////////////////////////////////////////////////
// @brief list of all rules
////////////////////////////////////////////////////////////////////////////////

std::map<int, Optimizer::Rule> Optimizer::_rules;

////////////////////////////////////////////////////////////////////////////////
// @brief lookup from rule name to rule level
////////////////////////////////////////////////////////////////////////////////

std::unordered_map<std::string, int> Optimizer::_ruleLookup;

// -----------------------------------------------------------------------------
// --SECTION--                                        constructors / destructors
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
// @brief constructor, this will initialize the rules database
////////////////////////////////////////////////////////////////////////////////

Optimizer::Optimizer (size_t maxNumberOfPlans)
  : _maxNumberOfPlans(maxNumberOfPlans > 0 ? maxNumberOfPlans : DefaultMaxNumberOfPlans) {

  if (_rules.empty()) {
    setupRules();
  }
}

// -----------------------------------------------------------------------------
// --SECTION--                                                    public methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
// @brief add a plan to the optimizer
////////////////////////////////////////////////////////////////////////////////

bool Optimizer::addPlan (ExecutionPlan* plan,
                         RuleLevel level,
                         bool wasModified) {
  TRI_ASSERT(plan != nullptr);

  _newPlans.push_back(plan, level);

  if (wasModified) {
    // register which rules modified / created the plan
    plan->addAppliedRule(_currentRule);
    plan->invalidateCost();
  }

  if (_newPlans.size() >= _maxNumberOfPlans) {
    return false;
  }

  return true;
}

////////////////////////////////////////////////////////////////////////////////
// @brief the actual optimization
////////////////////////////////////////////////////////////////////////////////

int Optimizer::createPlans (ExecutionPlan* plan,
                            std::vector<std::string> const& rulesSpecification,
                            bool inspectSimplePlans) {
  if (! inspectSimplePlans &&
      ! ExecutionEngine::isCoordinator() &&
      plan->isDeadSimple()) {
    // the plan is so simple that any further optimizations would probably cost
    // more than simply executing the plan
    _plans.clear();
    _plans.push_back(plan, 0);
    estimatePlans();

    return TRI_ERROR_NO_ERROR;
  }

  bool runOnlyRequiredRules = false;
  int leastDoneLevel = 0;

  TRI_ASSERT(! _rules.empty());
  int maxRuleLevel = _rules.rbegin()->first;

  // which optimizer rules are disabled?
  std::unordered_set<int> const&& disabledIds = getDisabledRuleIds(rulesSpecification);

  // _plans contains the previous optimisation result
  _plans.clear();
  _plans.push_back(plan, 0);

  _newPlans.clear();

  while (leastDoneLevel < maxRuleLevel) {
    // Find variable usage for all old plans now:
    for (auto p : _plans.list) {
      if (! p->varUsageComputed()) {
        p->findVarUsage();
      }
    }

    // std::cout << "Have " << _plans.size() << " plans:" << std::endl;
    /*
    for (auto p : _plans.list) {
      p->show();
      std::cout << std::endl;
    }
    */

    // int count = 0;

    // For all current plans:
    while (_plans.size() > 0) {
      int level;
      auto p = _plans.pop_front(level);

      if (level >= maxRuleLevel) {
        _newPlans.push_back(p, level);  // nothing to do, just keep it
      }
      else {   // find next rule
        auto it = _rules.upper_bound(level);
        TRI_ASSERT(it != _rules.end());

        /*
        std::cout << "Trying rule " << it->second.name << " with level "
                  << it->first << " on plan " << count++
                  << std::endl;
        */

        level = (*it).first;
        if ((runOnlyRequiredRules || disabledIds.find(level) != disabledIds.end()) &&
            (*it).second.canBeDisabled) {
          // we picked a disabled rule or we have reached the max number of plans
          // and just skip this rule
          level = it->first;

          _newPlans.push_back(p, level);  // nothing to do, just keep it
          // now try next
          continue;
        }

        _currentRule = level;

        int res;
        try {
          res = (*it).second.func(this, p, &(it->second));
        }
        catch (...) {
          delete p;
          throw;
        }

        if (res != TRI_ERROR_NO_ERROR) {
          return res;
        }
      }

      // TODO: abort early here if we found a good-enough plan
      // a good-enough plan is probably every plan with costs below some
      // defined threshold. this requires plan costs to be calculated here
    }

    _plans.steal(_newPlans);
    leastDoneLevel = maxRuleLevel;
    for (auto l : _plans.levelDone) {
      if (l < leastDoneLevel) {
        leastDoneLevel = l;
      }
    }
    // std::cout << "Least done level is " << leastDoneLevel << std::endl;

    // Stop if the result gets out of hand:
    if (! runOnlyRequiredRules &&
        _plans.size() >= _maxNumberOfPlans) {
      // must still iterate over all REQUIRED remaining transformation rules
      // because there are some rules which are required to make the query
      // work in cluster mode
      runOnlyRequiredRules = true;
    }
  }

  TRI_ASSERT(_plans.size() >= 1);

  estimatePlans();
  sortPlans();
#if 0
  // Only for debugging:
  std::cout << "Optimisation ends with " << _plans.size() << " plans."
            << std::endl;
  for (auto p : _plans.list) {
    p->show();
    std::cout << "costing: " << p->getCost() << std::endl;
    std::cout << std::endl;
  }
#endif

  return TRI_ERROR_NO_ERROR;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief translate a list of rule ids into rule name
////////////////////////////////////////////////////////////////////////////////

std::vector<std::string> Optimizer::translateRules (std::vector<int> const& rules) {
  std::vector<std::string> names;

  for (auto r : rules) {
    auto it = _rules.find(r);
    if (it != _rules.end()) {
      names.emplace_back((*it).second.name);
    }
  }
  return names;
}

// -----------------------------------------------------------------------------
// --SECTION--                                                   private methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief estimatePlans
////////////////////////////////////////////////////////////////////////////////

void Optimizer::estimatePlans () {
  for (auto p : _plans.list) {
    p->getCost();
    // this value is cached in the plan, so formally this step is
    // unnecessary, but for the sake of cleanliness...
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief sortPlans
////////////////////////////////////////////////////////////////////////////////

void Optimizer::sortPlans () {
  std::sort(_plans.list.begin(), _plans.list.end(), [](ExecutionPlan* const& a, ExecutionPlan* const& b) -> bool {
    return a->getCost() < b->getCost();
  });
}

////////////////////////////////////////////////////////////////////////////////
/// @brief look up the ids of all disabled rules
////////////////////////////////////////////////////////////////////////////////

std::unordered_set<int> Optimizer::getDisabledRuleIds (std::vector<std::string> const& names) const {
  std::unordered_set<int> disabled;

  // lookup ids of all disabled rules
  for (auto name : names) {
    if (name[0] == '-') {
      // disable rule
      if (name == "-all") {
        // disable all rules
        for (auto it : _rules) {
          disabled.insert(it.first);
        }
      }
      else {
        // disable a specific rule
        auto it = _ruleLookup.find(std::string(name.c_str() + 1));
        if (it != _ruleLookup.end()) {
          disabled.insert((*it).second);
        }
      }
    }
    else if (name[0] == '+') {
      // enable rule
      if (name == "+all") {
        // enable all rules
        disabled.clear();
      }
      else {
        auto it = _ruleLookup.find(std::string(name.c_str() + 1));
        if (it != _ruleLookup.end()) {
          disabled.erase((*it).second);
        }
      }
    }
  }

  return disabled;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief set up the optimizer rules once and forever
////////////////////////////////////////////////////////////////////////////////

void Optimizer::setupRules () {
  MUTEX_LOCKER(SetupLock);

  if (! _rules.empty()) {
    // race condition... prevent duplicate registration of rules
    return;
  }

  // List all the rules in the system here:
  // lower level values mean earlier rule execution

  // note that levels must be unique

  //////////////////////////////////////////////////////////////////////////////
  // "Pass 1": moving nodes "up" (potentially outside loops):
  //           please use levels between 1 and 99 here
  //////////////////////////////////////////////////////////////////////////////

  // move calculations up the dependency chain (to pull them out of
  // inner loops etc.)
  registerRule("move-calculations-up",
               moveCalculationsUpRule,
               moveCalculationsUpRule_pass1,
               true);

  // move filters up the dependency chain (to make result sets as small
  // as possible as early as possible)
  registerRule("move-filters-up",
               moveFiltersUpRule,
               moveFiltersUpRule_pass1,
               true);

  // remove redundant calculations
  registerRule("remove-redundant-calculations",
               removeRedundantCalculationsRule,
               removeRedundantCalculationsRule_pass1,
               true);

  //////////////////////////////////////////////////////////////////////////////
  /// "Pass 2": try to remove redundant or unnecessary nodes
  ///           use levels between 101 and 199 for this
  //////////////////////////////////////////////////////////////////////////////

  // remove filters from the query that are not necessary at all
  // filters that are always true will be removed entirely
  // filters that are always false will be replaced with a NoResults node
  registerRule("remove-unnecessary-filters",
               removeUnnecessaryFiltersRule,
               removeUnnecessaryFiltersRule_pass2,
               true);

  // remove calculations that are never necessary
  registerRule("remove-unnecessary-calculations",
               removeUnnecessaryCalculationsRule,
               removeUnnecessaryCalculationsRule_pass2,
               true);

  // remove redundant sort blocks
  registerRule("remove-redundant-sorts",
               removeRedundantSorts,
               removeRedundantSorts_pass2,
               true);

  //////////////////////////////////////////////////////////////////////////////
  /// "Pass 3": interchange EnumerateCollection nodes in all possible ways
  ///           this is level 500, please never let new plans from higher
  ///           levels go back to this or lower levels!
  //////////////////////////////////////////////////////////////////////////////

  registerRule("interchange-adjacent-enumerations",
               interchangeAdjacentEnumerations,
               interchangeAdjacentEnumerations_pass3,
               true);

  //////////////////////////////////////////////////////////////////////////////
  // "Pass 4": moving nodes "up" (potentially outside loops) (second try):
  //           please use levels between 501 and 599 here
  //////////////////////////////////////////////////////////////////////////////

  // move calculations up the dependency chain (to pull them out of
  // inner loops etc.)
  registerRule("move-calculations-up-2",
               moveCalculationsUpRule,
               moveCalculationsUpRule_pass4,
               true);

  // move filters up the dependency chain (to make result sets as small
  // as possible as early as possible)
  registerRule("move-filters-up-2",
               moveFiltersUpRule,
               moveFiltersUpRule_pass4,
               true);

  //////////////////////////////////////////////////////////////////////////////
  /// "Pass 5": try to remove redundant or unnecessary nodes (second try)
  ///           use levels between 601 and 699 for this
  //////////////////////////////////////////////////////////////////////////////

  // remove filters from the query that are not necessary at all
  // filters that are always true will be removed entirely
  // filters that are always false will be replaced with a NoResults node
  registerRule("remove-unnecessary-filters-2",
               removeUnnecessaryFiltersRule,
               removeUnnecessaryFiltersRule_pass5,
               true);

  // remove calculations that are never necessary
  registerRule("remove-unnecessary-calculations-2",
               removeUnnecessaryCalculationsRule,
               removeUnnecessaryCalculationsRule_pass5,
               true);

  // remove redundant sort blocks
  registerRule("remove-redundant-sorts-2",
               removeRedundantSorts,
               removeRedundantSorts_pass5,
               true);

  //////////////////////////////////////////////////////////////////////////////
  /// "Pass 6": use indexes if possible for FILTER and/or SORT nodes
  ///           use levels between 701 and 799 for this
  //////////////////////////////////////////////////////////////////////////////

  // try to find a filter after an enumerate collection and find an index . . .
  registerRule("use-index-range",
               useIndexRange,
               useIndexRange_pass6,
               true);

  // try to find sort blocks which are superseeded by indexes
  registerRule("use-index-for-sort",
               useIndexForSort,
               useIndexForSort_pass6,
               true);

  if (ExecutionEngine::isCoordinator()) {
    // distribute operations in cluster
    registerRule("scatter-in-cluster",
                 scatterInCluster,
                 scatterInCluster_pass10,
                 false);

    registerRule("distribute-in-cluster",
                 distributeInCluster,
                 distributeInCluster_pass10,
                 false);

    // distribute operations in cluster
    registerRule("distribute-filtercalc-to-cluster",
                 distributeFilternCalcToCluster,
                 distributeFilternCalcToCluster_pass10,
                 true);

    registerRule("distribute-sort-to-cluster",
                 distributeSortToCluster,
                 distributeSortToCluster_pass10,
                 true);

    registerRule("remove-unnecessary-remote-scatter",
                 removeUnnecessaryRemoteScatter,
                 removeUnnecessaryRemoteScatter_pass10,
                 true);

    registerRule("undistribute-remove-after-enum-coll",
                 undistributeRemoveAfterEnumColl,
                 undistributeRemoveAfterEnumColl_pass10,
                 true);

  }
}

// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)"
// End:

<|endoftext|>


<commit_before>/*****************************************************************************
 * Project: RooFit                                                           *
 * Package: RooFitModels                                                     *
 *    File: $Id$
 * Authors:                                                                  *
 *   GR, Gerhard Raven,   Nikhef & VU, Gerhard.Raven@nikhef.nl
 *                                                                           *
 * Copyright (c) 2010, Nikhef & VU. All rights reserved.
 *                                                                           *
 * Redistribution and use in source and binary forms,                        *
 * with or without modification, are permitted according to the terms        *
 * listed in LICENSE (http://roofit.sourceforge.net/license.txt)             *
 *****************************************************************************/

//////////////////////////////////////////////////////////////////////////////
//
// BEGIN_HTML
// END_HTML
//

#include "RooFit.h"
#include "Riostream.h"
#include <math.h>

#include "RooLegendre.h"
#include "RooAbsReal.h"
#include "Math/SpecFunc.h"
#include "TMath.h"

ClassImp(RooLegendre)
;

//_____________________________________________________________________________
namespace {
    inline double a(int p, int l, int m) {
        double r = TMath::Factorial(l+m)/TMath::Factorial(m+p)/TMath::Factorial(p)/TMath::Factorial(l-m-2*p);
        r /= pow(2.,m+2*p);
        return p%2==0 ? r : -r ;
    }
}

//_____________________________________________________________________________
RooLegendre::RooLegendre()
{
}

//_____________________________________________________________________________
RooLegendre::RooLegendre(const char* name, const char* title, RooAbsReal& ctheta, int l, int m)
 : RooAbsReal(name, title)
 , _ctheta("ctheta", "ctheta", this, ctheta)
 , _l1(l),_m1(m),_l2(0),_m2(0)
{
  //TODO: for now, we assume that ctheta has a range [-1,1]
  // should map the ctheta range onto this interval, and adjust integrals...

  //TODO: we assume m>=0
  //      should map m<0 back to m>=0...
}

//_____________________________________________________________________________
RooLegendre::RooLegendre(const char* name, const char* title, RooAbsReal& ctheta, int l1, int m1, int l2, int m2)
 : RooAbsReal(name, title)
 , _ctheta("ctheta", "ctheta", this, ctheta)
 , _l1(l1),_m1(m1),_l2(l2),_m2(m2)
{
}

//_____________________________________________________________________________
RooLegendre::RooLegendre(const RooLegendre& other, const char* name)
    : RooAbsReal(other, name)
    , _ctheta("ctheta", this, other._ctheta)
    , _l1(other._l1), _m1(other._m1)
    , _l2(other._l2), _m2(other._m2)
{
}

//_____________________________________________________________________________
Double_t RooLegendre::evaluate() const
{
  // TODO: check that 0<=m_i<=l_i; on the other hand, assoc_legendre already does that ;-)
  // Note: P_0^0 = 1, so P_l^m = P_l^m P_0^0
  double r = 1;
  if (_l1!=0||_m1!=0) r *= ROOT::Math::assoc_legendre(_l1,_m1,_ctheta);
  if (_l2!=0||_m2!=0) r *= ROOT::Math::assoc_legendre(_l2,_m2,_ctheta);
  if ((_m1+_m2)%2==1) r = -r;
  return r;
}

//_____________________________________________________________________________
Int_t RooLegendre::getAnalyticalIntegral(RooArgSet& allVars, RooArgSet& analVars, const char* rangeName) const
{
  // don't support indefinite integrals...
  if (rangeName && strlen(rangeName) ) return 0;
  if (matchArgs(allVars, analVars, _ctheta)) return 1;
  return 0;
}

//_____________________________________________________________________________
Double_t RooLegendre::analyticalIntegral(Int_t code, const char* ) const
{
  // this was verified to match mathematica for
  // l1 in [0,2], m1 in [0,l1], l2 in [l1,4], m2 in [0,l2]
  assert(code==1) ;
  if ( _m1==_m2 )                 return ( _l1 == _l2) ?  TMath::Factorial(_l1+_m2)/TMath::Factorial(_l1-_m1)*double(2)/(2*_l1+1) : 0.;
  if ( (_l1+_l2-_m1-_m2)%2 != 0 ) return 0; // these combinations are odd under x -> -x

  // from B.R. Wong, "On the overlap integral of associated Legendre Polynomials" 1998 J. Phys. A: Math. Gen. 31 1101
  // Note: this paper gets the sign wrong if _m1+_m2 is odd..
  // TODO: update to the result of http://iopscience.iop.org/0305-4470/32/13/011/pdf/0305-4470_32_13_011.pdf
  double r=0;
  for (int p1=0; 2*p1 <= _l1-_m1 ;++p1) {
    double a1 = a(p1,_l1,_m1);
    for (int p2=0; 2*p2 <= _l2-_m2 ; ++p2) {
       double a2 = a(p2,_l2,_m2);
       r+= a1*a2*TMath::Gamma( double(_l1+_l2-_m1-_m2-2*p1-2*p2+1)/2 )*TMath::Gamma( double(_m1+_m2+2*p1+2*p2+2)/2 );
    }
  }
  r /= TMath::Gamma( double(_l1+_l2+3)/2 );

  if ((_m1+_m2)%2==1) r = -r;
  return r;
}

Int_t RooLegendre::getMaxVal( const RooArgSet& /*vars*/) const {
    if (_m1==0&&_m2==0) return 1;
    // does anyone know the analytical expression for the  max values in case m!=0??
    if (_l1<3&&_l2<3) return 1;
    return 0;
}

namespace {
    inline double maxSingle(int i, int j) {
        assert(j<=i);
        //   x0 : 1 (ordinary Legendre)
        if (j==0) return 1;
        assert(i<3);
        //   11: 1
        if (i<2) return 1;
        //   21: 3   22: 3
        static const double m2[3] = { 3,3 };
        return m2[j-1];
    }
}
Double_t RooLegendre::maxVal( Int_t /*code*/) const {
    return maxSingle(_l1,_m1)*maxSingle(_l2,_m2);
}
<commit_msg><commit_after>/*****************************************************************************
 * Project: RooFit                                                           *
 * Package: RooFitModels                                                     *
 *    File: $Id$
 * Authors:                                                                  *
 *   GR, Gerhard Raven,   Nikhef & VU, Gerhard.Raven@nikhef.nl
 *                                                                           *
 * Copyright (c) 2010, Nikhef & VU. All rights reserved.
 *                                                                           *
 * Redistribution and use in source and binary forms,                        *
 * with or without modification, are permitted according to the terms        *
 * listed in LICENSE (http://roofit.sourceforge.net/license.txt)             *
 *****************************************************************************/

//////////////////////////////////////////////////////////////////////////////
//
// BEGIN_HTML
// END_HTML
//

#include "RooFit.h"
#include "Riostream.h"
#include <math.h>
#include <string>

#include "RooLegendre.h"
#include "RooAbsReal.h"
#include "Math/SpecFunc.h"
#include "TMath.h"

ClassImp(RooLegendre)
;

//_____________________________________________________________________________
namespace {
    inline double a(int p, int l, int m) {
        double r = TMath::Factorial(l+m)/TMath::Factorial(m+p)/TMath::Factorial(p)/TMath::Factorial(l-m-2*p);
        r /= pow(2.,m+2*p);
        return p%2==0 ? r : -r ;
    }
}

//_____________________________________________________________________________
RooLegendre::RooLegendre()
{
}

//_____________________________________________________________________________
RooLegendre::RooLegendre(const char* name, const char* title, RooAbsReal& ctheta, int l, int m)
 : RooAbsReal(name, title)
 , _ctheta("ctheta", "ctheta", this, ctheta)
 , _l1(l),_m1(m),_l2(0),_m2(0)
{
  //TODO: for now, we assume that ctheta has a range [-1,1]
  // should map the ctheta range onto this interval, and adjust integrals...

  //TODO: we assume m>=0
  //      should map m<0 back to m>=0...
}

//_____________________________________________________________________________
RooLegendre::RooLegendre(const char* name, const char* title, RooAbsReal& ctheta, int l1, int m1, int l2, int m2)
 : RooAbsReal(name, title)
 , _ctheta("ctheta", "ctheta", this, ctheta)
 , _l1(l1),_m1(m1),_l2(l2),_m2(m2)
{
}

//_____________________________________________________________________________
RooLegendre::RooLegendre(const RooLegendre& other, const char* name)
    : RooAbsReal(other, name)
    , _ctheta("ctheta", this, other._ctheta)
    , _l1(other._l1), _m1(other._m1)
    , _l2(other._l2), _m2(other._m2)
{
}

//_____________________________________________________________________________
Double_t RooLegendre::evaluate() const
{
  // TODO: check that 0<=m_i<=l_i; on the other hand, assoc_legendre already does that ;-)
  // Note: P_0^0 = 1, so P_l^m = P_l^m P_0^0
#ifdef MATHMORE
  double r = 1;
  if (_l1!=0||_m1!=0) r *= ROOT::Math::assoc_legendre(_l1,_m1,_ctheta);
  if (_l2!=0||_m2!=0) r *= ROOT::Math::assoc_legendre(_l2,_m2,_ctheta);
  if ((_m1+_m2)%2==1) r = -r;
  return r;
#else
  throw std::string("RooLegendre: ERROR: This class require installation of the MathMore library") ;
  return 0 ;
#endif
}

//_____________________________________________________________________________
Int_t RooLegendre::getAnalyticalIntegral(RooArgSet& allVars, RooArgSet& analVars, const char* rangeName) const
{
  // don't support indefinite integrals...
  if (rangeName && strlen(rangeName) ) return 0;
  if (matchArgs(allVars, analVars, _ctheta)) return 1;
  return 0;
}

//_____________________________________________________________________________
Double_t RooLegendre::analyticalIntegral(Int_t code, const char* ) const
{
  // this was verified to match mathematica for
  // l1 in [0,2], m1 in [0,l1], l2 in [l1,4], m2 in [0,l2]
  assert(code==1) ;
  if ( _m1==_m2 )                 return ( _l1 == _l2) ?  TMath::Factorial(_l1+_m2)/TMath::Factorial(_l1-_m1)*double(2)/(2*_l1+1) : 0.;
  if ( (_l1+_l2-_m1-_m2)%2 != 0 ) return 0; // these combinations are odd under x -> -x

  // from B.R. Wong, "On the overlap integral of associated Legendre Polynomials" 1998 J. Phys. A: Math. Gen. 31 1101
  // Note: this paper gets the sign wrong if _m1+_m2 is odd..
  // TODO: update to the result of http://iopscience.iop.org/0305-4470/32/13/011/pdf/0305-4470_32_13_011.pdf
  double r=0;
  for (int p1=0; 2*p1 <= _l1-_m1 ;++p1) {
    double a1 = a(p1,_l1,_m1);
    for (int p2=0; 2*p2 <= _l2-_m2 ; ++p2) {
       double a2 = a(p2,_l2,_m2);
       r+= a1*a2*TMath::Gamma( double(_l1+_l2-_m1-_m2-2*p1-2*p2+1)/2 )*TMath::Gamma( double(_m1+_m2+2*p1+2*p2+2)/2 );
    }
  }
  r /= TMath::Gamma( double(_l1+_l2+3)/2 );

  if ((_m1+_m2)%2==1) r = -r;
  return r;
}

Int_t RooLegendre::getMaxVal( const RooArgSet& /*vars*/) const {
    if (_m1==0&&_m2==0) return 1;
    // does anyone know the analytical expression for the  max values in case m!=0??
    if (_l1<3&&_l2<3) return 1;
    return 0;
}

namespace {
    inline double maxSingle(int i, int j) {
        assert(j<=i);
        //   x0 : 1 (ordinary Legendre)
        if (j==0) return 1;
        assert(i<3);
        //   11: 1
        if (i<2) return 1;
        //   21: 3   22: 3
        static const double m2[3] = { 3,3 };
        return m2[j-1];
    }
}
Double_t RooLegendre::maxVal( Int_t /*code*/) const {
    return maxSingle(_l1,_m1)*maxSingle(_l2,_m2);
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: inwnt.cxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: vg $ $Date: 2006-04-07 14:38:15 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _SAL_CONFIG_H_
#include <sal/config.h>
#endif

#include <windef.h>     // needed by winnls.h
#include <winbase.h>    // needed by winnls.h
#include <winnls.h>

#ifndef INCLUDED_RTL_INSTANCE_HXX
#include <rtl/instance.hxx>
#endif

#ifndef INCLUDED_I18NPOOL_MSLANGID_HXX
#include "i18npool/mslangid.hxx"
#endif

static LanguageType nImplSystemLanguage = LANGUAGE_DONTKNOW;
static LanguageType nImplSystemUILanguage = LANGUAGE_DONTKNOW;

// =======================================================================

static LanguageType GetSVLang( LANGID nWinLangId )
{
    // No Translation, we work with the original MS code without the SORT_ID.
    // So we can get never LANG-ID's from MS, which are currently not defined
    // by us.
    return LanguageType( static_cast<sal_uInt16>(nWinLangId & 0xffff));
}

// -----------------------------------------------------------------------

typedef LANGID (WINAPI *getLangFromEnv)();

static void getPlatformSystemLanguageImpl( LanguageType& rSystemLanguage,
        getLangFromEnv pGetUserDefault, getLangFromEnv pGetSystemDefault )
{
    LanguageType nLang = rSystemLanguage;
    if ( nLang == LANGUAGE_DONTKNOW )
    {
        ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex());
        nLang = rSystemLanguage;
        if ( nLang == LANGUAGE_DONTKNOW )
        {
            LANGID nLangId;

            nLangId = (pGetUserDefault)();
            nLang = GetSVLang( nLangId );

            if ( nLang == LANGUAGE_DONTKNOW )
            {
                nLangId = (pGetSystemDefault)();
                nLang = GetSVLang( nLangId );
            }
            OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
            rSystemLanguage = nLang;
        }
        else
            OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
    }
}

// -----------------------------------------------------------------------

LanguageType MsLangId::getPlatformSystemLanguage()
{
    getPlatformSystemLanguageImpl( nImplSystemLanguage,
            &GetUserDefaultLangID, &GetSystemDefaultLangID);
    return nImplSystemLanguage;
}

// -----------------------------------------------------------------------

LanguageType MsLangId::getPlatformSystemUILanguage()
{
    // TODO: this could be distinguished, #if(WINVER >= 0x0500)
    // needs _run_ time differentiation though, not at compile time.
#if 0
    getPlatformSystemLanguageImpl( nImplSystemUILanguage,
            &GetUserDefaultUILanguage, &GetSystemDefaultUILanguage);
#endif
    getPlatformSystemLanguageImpl( nImplSystemUILanguage,
            &GetUserDefaultLangID, &GetSystemDefaultLangID);
    return nImplSystemUILanguage;
}
<commit_msg>INTEGRATION: CWS warnings01 (1.2.18); FILE MERGED 2006/05/29 09:59:28 sb 1.2.18.1: #i53898# Made code warning-free and/or compile at all after resync to SRC680m170.<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: inwnt.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-20 04:46:25 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _SAL_CONFIG_H_
#include <sal/config.h>
#endif

#pragma warning(push,1) // disable warnings within system headers
#include <windef.h>     // needed by winnls.h
#include <winbase.h>    // needed by winnls.h
#include <winnls.h>
#pragma warning(pop)

#ifndef INCLUDED_RTL_INSTANCE_HXX
#include <rtl/instance.hxx>
#endif

#ifndef INCLUDED_I18NPOOL_MSLANGID_HXX
#include "i18npool/mslangid.hxx"
#endif

static LanguageType nImplSystemLanguage = LANGUAGE_DONTKNOW;
static LanguageType nImplSystemUILanguage = LANGUAGE_DONTKNOW;

// =======================================================================

static LanguageType GetSVLang( LANGID nWinLangId )
{
    // No Translation, we work with the original MS code without the SORT_ID.
    // So we can get never LANG-ID's from MS, which are currently not defined
    // by us.
    return LanguageType( static_cast<sal_uInt16>(nWinLangId & 0xffff));
}

// -----------------------------------------------------------------------

typedef LANGID (WINAPI *getLangFromEnv)();

static void getPlatformSystemLanguageImpl( LanguageType& rSystemLanguage,
        getLangFromEnv pGetUserDefault, getLangFromEnv pGetSystemDefault )
{
    LanguageType nLang = rSystemLanguage;
    if ( nLang == LANGUAGE_DONTKNOW )
    {
        ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex());
        nLang = rSystemLanguage;
        if ( nLang == LANGUAGE_DONTKNOW )
        {
            LANGID nLangId;

            nLangId = (pGetUserDefault)();
            nLang = GetSVLang( nLangId );

            if ( nLang == LANGUAGE_DONTKNOW )
            {
                nLangId = (pGetSystemDefault)();
                nLang = GetSVLang( nLangId );
            }
            OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
            rSystemLanguage = nLang;
        }
        else
            OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
    }
}

// -----------------------------------------------------------------------

LanguageType MsLangId::getPlatformSystemLanguage()
{
    getPlatformSystemLanguageImpl( nImplSystemLanguage,
            &GetUserDefaultLangID, &GetSystemDefaultLangID);
    return nImplSystemLanguage;
}

// -----------------------------------------------------------------------

LanguageType MsLangId::getPlatformSystemUILanguage()
{
    // TODO: this could be distinguished, #if(WINVER >= 0x0500)
    // needs _run_ time differentiation though, not at compile time.
#if 0
    getPlatformSystemLanguageImpl( nImplSystemUILanguage,
            &GetUserDefaultUILanguage, &GetSystemDefaultUILanguage);
#endif
    getPlatformSystemLanguageImpl( nImplSystemUILanguage,
            &GetUserDefaultLangID, &GetSystemDefaultLangID);
    return nImplSystemUILanguage;
}
<|endoftext|>


<commit_before>/** \copyright
 * Copyright (c) 2012, Stuart W Baker
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are  permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * \file HwInit.cxx
 * This file represents the interrupt vector table for TI Stellaris MCUs.
 *
 * @author Stuart W. Baker
 * @date 5 January 2013
 */

#define PART_LM4F120H5QR

#include <cstdint>
#include <new>

#include "inc/hw_types.h"
#include "inc/hw_memmap.h"
#include "inc/hw_ints.h"
#include "driverlib/rom.h"
#include "driverlib/rom_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "driverlib/timer.h"
#include "driverlib/interrupt.h"
#include "os/OS.hxx"
#include "StellarisDev.hxx"

/** override stdin */
const char *STDIN_DEVICE = "/dev/ser0";

/** override stdout */
const char *STDOUT_DEVICE = "/dev/ser0";

/** override stderr */
const char *STDERR_DEVICE = "/dev/ser0";

/** USB Device CDC serial driver instance */
static StellarisCdc cdc0("/dev/serUSB0");

/** UART 0 serial driver instance */
static StellarisUart uart0("/dev/ser0", UART0_BASE);

/** CAN 0 CAN driver instance */
static StellarisCan can0("/dev/can0", CAN0_BASE);

/** Blink LED */
extern "C" {
uint32_t blinker_pattern = 0;
static uint32_t rest_pattern = 0;

void resetblink(uint32_t pattern)
{
    blinker_pattern = pattern;
    /* make a timer event trigger immediately */
}

void timer5a_interrupt_handler(void)
{
    //
    // Clear the timer interrupt.
    //
    MAP_TimerIntClear(TIMER5_BASE, TIMER_TIMA_TIMEOUT);
    // Set output LED.
    MAP_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, (rest_pattern & 1) ? GPIO_PIN_1 : 0);
    // Shift and maybe reset pattern.
    rest_pattern >>= 1;
    if (!rest_pattern)
        rest_pattern = blinker_pattern;
}

void diewith(uint32_t pattern) {
    vPortClearInterruptMask( 0x20 );
    asm("cpsie i\n");

    resetblink(pattern);
    while(1);
}

}

/** Initialize the processor hardware.
 */
void hw_init(void)
{
    /* Globally disables interrupts until the FreeRTOS scheduler is up. */
    asm("cpsid i\n");

    /* Setup the system clock. */
    MAP_SysCtlClockSet( SYSCTL_SYSDIV_10 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ );

    /* Red LED pin initialization */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    MAP_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, GPIO_PIN_1);
    MAP_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1);
    MAP_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, GPIO_PIN_1);

    /* Blinker timer initialization. */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER5);
    MAP_TimerConfigure(TIMER5_BASE, TIMER_CFG_PERIODIC);
    MAP_TimerLoadSet(TIMER5_BASE, TIMER_A, MAP_SysCtlClockGet() / 8);
    MAP_IntEnable(INT_TIMER5A);
    /* This interrupt should hit even during kernel operations. */
    MAP_IntPrioritySet(INT_TIMER5A, 0);
    MAP_TimerIntEnable(TIMER5_BASE, TIMER_TIMA_TIMEOUT);
    MAP_TimerEnable(TIMER5_BASE, TIMER_A);

    /* UART0 pin initialization */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    MAP_GPIOPinConfigure(GPIO_PA0_U0RX);
    MAP_GPIOPinConfigure(GPIO_PA1_U0TX);
    MAP_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    /* USB0 pin initialization */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    MAP_GPIOPinTypeUSBAnalog(GPIO_PORTD_BASE, GPIO_PIN_5 | GPIO_PIN_4);

    /* CAN pin initialization */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
    MAP_GPIOPinConfigure(GPIO_PE4_CAN0RX);
    MAP_GPIOPinConfigure(GPIO_PE5_CAN0TX);
    MAP_GPIOPinTypeCAN(GPIO_PORTE_BASE, GPIO_PIN_4 | GPIO_PIN_5);

    /* Blue LED pin initialization */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    MAP_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_PIN_2);
    MAP_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_2);

    /* Green LED pin initialization */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    MAP_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, GPIO_PIN_3);
    MAP_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_3);

    /* Initialize timer0a interrupt */

    MAP_IntPrioritySet(INT_USB0, 0xff); // USB interrupt low priority

}

<commit_msg>Fixes style of HwInit.cxx<commit_after>/** \copyright
 * Copyright (c) 2012, Stuart W Baker
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are  permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * \file HwInit.cxx
 * This file represents the interrupt vector table for TI Stellaris MCUs.
 *
 * @author Stuart W. Baker
 * @date 5 January 2013
 */

#define PART_LM4F120H5QR

#include <cstdint>
#include <new>

#include "inc/hw_types.h"
#include "inc/hw_memmap.h"
#include "inc/hw_ints.h"
#include "driverlib/rom.h"
#include "driverlib/rom_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "driverlib/timer.h"
#include "driverlib/interrupt.h"
#include "os/OS.hxx"
#include "StellarisDev.hxx"

/** override stdin */
const char *STDIN_DEVICE = "/dev/ser0";

/** override stdout */
const char *STDOUT_DEVICE = "/dev/ser0";

/** override stderr */
const char *STDERR_DEVICE = "/dev/ser0";

/** USB Device CDC serial driver instance */
static StellarisCdc cdc0("/dev/serUSB0");

/** UART 0 serial driver instance */
static StellarisUart uart0("/dev/ser0", UART0_BASE);

/** CAN 0 CAN driver instance */
static StellarisCan can0("/dev/can0", CAN0_BASE);

/** Blink LED */
extern "C" {
uint32_t blinker_pattern = 0;
static uint32_t rest_pattern = 0;

void resetblink(uint32_t pattern)
{
    blinker_pattern = pattern;
    /* make a timer event trigger immediately */
}

void timer5a_interrupt_handler(void)
{
    //
    // Clear the timer interrupt.
    //
    MAP_TimerIntClear(TIMER5_BASE, TIMER_TIMA_TIMEOUT);
    // Set output LED.
    MAP_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1,
                     (rest_pattern & 1) ? GPIO_PIN_1 : 0);
    // Shift and maybe reset pattern.
    rest_pattern >>= 1;
    if (!rest_pattern)
        rest_pattern = blinker_pattern;
}

void diewith(uint32_t pattern)
{
    vPortClearInterruptMask(0x20);
    asm("cpsie i\n");

    resetblink(pattern);
    while (1)
        ;
}
}

/** Initialize the processor hardware.
 */
void hw_init(void)
{
    /* Globally disables interrupts until the FreeRTOS scheduler is up. */
    asm("cpsid i\n");

    /* Setup the system clock. */
    MAP_SysCtlClockSet(SYSCTL_SYSDIV_10 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |
                       SYSCTL_XTAL_16MHZ);

    /* Red LED pin initialization */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    MAP_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, GPIO_PIN_1);
    MAP_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1);
    MAP_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, GPIO_PIN_1);

    /* Blinker timer initialization. */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER5);
    MAP_TimerConfigure(TIMER5_BASE, TIMER_CFG_PERIODIC);
    MAP_TimerLoadSet(TIMER5_BASE, TIMER_A, MAP_SysCtlClockGet() / 8);
    MAP_IntEnable(INT_TIMER5A);
    /* This interrupt should hit even during kernel operations. */
    MAP_IntPrioritySet(INT_TIMER5A, 0);
    MAP_TimerIntEnable(TIMER5_BASE, TIMER_TIMA_TIMEOUT);
    MAP_TimerEnable(TIMER5_BASE, TIMER_A);

    /* UART0 pin initialization */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    MAP_GPIOPinConfigure(GPIO_PA0_U0RX);
    MAP_GPIOPinConfigure(GPIO_PA1_U0TX);
    MAP_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    /* USB0 pin initialization */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    MAP_GPIOPinTypeUSBAnalog(GPIO_PORTD_BASE, GPIO_PIN_5 | GPIO_PIN_4);

    /* CAN pin initialization */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
    MAP_GPIOPinConfigure(GPIO_PE4_CAN0RX);
    MAP_GPIOPinConfigure(GPIO_PE5_CAN0TX);
    MAP_GPIOPinTypeCAN(GPIO_PORTE_BASE, GPIO_PIN_4 | GPIO_PIN_5);

    /* Blue LED pin initialization */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    MAP_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_PIN_2);
    MAP_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_2);

    /* Green LED pin initialization */
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    MAP_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, GPIO_PIN_3);
    MAP_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_3);

    /* Initialize timer0a interrupt */

    MAP_IntPrioritySet(INT_USB0, 0xff); // USB interrupt low priority
}
<|endoftext|>


<commit_before>/*-------------FDTD.cpp-------------------------------------------------------//
*
*              Finite Difference Time Domain
*
* Purpose: To replicate the results of our invisible lense raytracer with
*          FDTD. Woo!
*
*   Notes: Most of this is coming from the following link:
*             http://www.eecs.wsu.edu/~schneidj/ufdtd/chap3.pdf
*             http://www.eecs.wsu.edu/~schneidj/ufdtd/chap8.pdf
*
*-----------------------------------------------------------------------------*/

#include <iostream>
#include <vector>
#include <cmath>
#include <fstream>

static const size_t space = 200;

struct Bound{
    int x,y;
};

struct Loss{
    std::vector <double> EzH = std::vector<double>(space * space, 0),
                         EzE = std::vector<double>(space * space, 0),
                         HyE = std::vector<double>(space * space, 0),
                         HyH = std::vector<double>(space * space, 0),
                         HxE = std::vector<double>(space * space, 0),
                         HxH = std::vector<double>(space * space, 0);
};

struct Loss1d{
    std::vector <double> EzH = std::vector<double>(space, 0),
                         EzE = std::vector<double>(space, 0),
                         HyE = std::vector<double>(space, 0),
                         HyH = std::vector<double>(space, 0),
                         HxE = std::vector<double>(space, 0),
                         HxH = std::vector<double>(space, 0);
};

struct Field{
    std::vector <double> Hx = std::vector<double>(space * space, 0),
                         Hy = std::vector<double>(space * space, 0),
                         Ez = std::vector<double>(space * space, 0);
    int t;
};

struct Field1d{
    std::vector <double> Hx = std::vector<double>(space, 0),
                         Hy = std::vector<double>(space, 0),
                         Ez = std::vector<double>(space, 0);
};

#define EzH(i, j) EzH[(i) + (j) *  space]
#define EzE(i, j) EzE[(i) + (j) *  space]
#define HyH(i, j) HyH[(i) + (j) *  space]
#define HyE(i, j) HyE[(i) + (j) *  space]
#define HxH(i, j) HxH[(i) + (j) *  space]
#define HxE(i, j) HxE[(i) + (j) *  space]
#define Hx(i, j) Hx[(i) + (j) *  space]
#define Hy(i, j) Hy[(i) + (j) *  space]
#define Ez(i, j) Ez[(i) + (j) *  space]

void FDTD(Field EM, Field1d EM1d,
          const int final_time, const double eps, const int space,
          std::ofstream& output);

// Adding ricker solutuion
double ricker(int time, int loc, double Cour);

// 2 dimensional functions for E / H movement
Field Hupdate2d(Field EM, Loss lass, int t);
Field Eupdate2d(Field EM, Loss lass, int t);

// 1 dimensional update functions for E / H
Field1d Hupdate1d(Field1d EM1d, Loss lass, int t);
Field1d Eupdate1d(Field1d EM1d, Loss lass, int t);

// Creating loss
Loss createloss2d(Loss lass, double eps, double Cour, double loss);
Loss1d createloss1d(Loss1d lass1d, double eps, double Cour, double loss);

// TFSF boundaries
Field TFSF(Field EM, Loss lass, Field1d EM1d, Loss1d lass1d, double Cour);

/*----------------------------------------------------------------------------//
* MAIN
*-----------------------------------------------------------------------------*/

int main(){

    // defines output
    std::ofstream output("FDTD.dat", std::ofstream::out);

    int final_time = 1000;
    double eps = 377.0;

    // define initial E and H fields
    // std::vector<double> Ez(space, 0.0), Hy(space, 0.0);
    Field EM;
    Field1d EM1d;
    EM.t = 0;

    FDTD(EM, EM1d, final_time, eps, space, output);

}

/*----------------------------------------------------------------------------//
* SUBROUTINES
*-----------------------------------------------------------------------------*/

// This is the function we writs the bulk of the code in
void FDTD(Field EM, Field1d EM1d,
          const int final_time, const double eps, const int space,
          std::ofstream& output){

    // For magnetic field:
    // double offset = 0.00005;

    // for electric field:
    //double offset = 0.05;
    double loss = 0.0;
    double Cour = 1.0 / sqrt(2.0);

    Loss lass;
    lass  = createloss2d(lass, eps, Cour, loss);
    Loss1d lass1d;
    lass1d = createloss1d(lass1d, eps, Cour, loss);

    // Time looping
    for (int t = 0; t < final_time; t++){

        EM = Hupdate2d(EM, lass, t);
        EM = TFSF(EM, lass, EM1d, lass1d, Cour);
        EM = Eupdate2d(EM,lass,t);
        //EM.Ez(0,100) = ricker(t, 0, Cour);

        // Outputting to a file
        int check = 5;
        if (t % check == 0){
            for (int dx = 0; dx < space; dx = dx + check){
                for (int dy = 0; dy < space; dy = dy + check){
                    output << t << '\t' << dx <<'\t' << dy << '\t'
                           << EM.Ez(dx, dy) << '\t' << EM.Hy(dx, dy)
                           << '\t' << EM.Hx(dx, dy) << '\t' << '\n';
                    //output << Ez(dx,dy) + (t * offset) << '\n';
                    //output << Hy[dx] + (t * offset) << '\n';
                }
            }

            output << '\n' << '\n';
        }

    }
}

// Adding the ricker solution
double ricker(int time, int loc, double Cour){
    double Ricky;
    double temp_const = 3.14159*((Cour*(double)time - (double)loc)/20.0 - 1.0);
    temp_const = temp_const * temp_const;
    Ricky = (1.0 - 2.0 * temp_const) * exp(-temp_const);
    return Ricky;

}

// 2 dimensional functions for E / H movement
Field Hupdate2d(Field EM, Loss lass, int t){
    // update magnetic field, x direction
    for (size_t dx = 0; dx < space; dx++){
        for (size_t dy = 0; dy < space - 1; dy++){
           EM.Hx(dx,dy) = lass.HxH(dx,dy) * EM.Hx(dx, dy)
                       - lass.HxE(dx,dy) * (EM.Ez(dx,dy + 1)
                                            - EM.Ez(dx,dy));
        }
    }

    // update magnetic field, y direction
    for (size_t dx = 0; dx < space - 1; dx++){
        for (size_t dy = 0; dy < space; dy++){
           EM.Hy(dx,dy) = lass.HyH(dx,dy) * EM.Hy(dx,dy)
                      + lass.HyE(dx,dy) * (EM.Ez(dx + 1,dy)
                                            - EM.Ez(dx,dy));
        }
    }

    return EM;

}

Field Eupdate2d(Field EM, Loss lass, int t){
    // update electric field
    for (size_t dx = 1; dx < space - 1; dx++){
        for (size_t dy = 1; dy < space - 1; dy++){
           EM.Ez(dx,dy) = lass.EzE(dx,dy) * EM.Ez(dx,dy)
                       + lass.EzH(dx,dy) * ((EM.Hy(dx, dy)
                                         - EM.Hy(dx - 1, dy))
                                         - (EM.Hx(dx,dy)
                                         - EM.Hx(dx, dy - 1)));
        }
    }
    return EM;
}

// 1 dimensional update functions for E / H
Field1d Hupdate1d(Field1d EM1d, Loss1d lass1d, int t){
    // update magnetic field, y direction
    for (size_t dx = 0; dx < space - 1; dx++){
        EM1d.Hy[dx] = lass1d.HyH[dx] * EM1d.Hy[dx]
                  + lass1d.HyE[dx] * (EM1d.Ez[dx + 1] - EM1d.Ez[dx]);
    }

    return EM1d;
}

Field1d Eupdate1d(Field1d EM1d, Loss1d lass1d, int t){
    // update electric field, y direction
    for (size_t dx = 1; dx < space - 1; dx++){
        EM1d.Ez[dx] = lass1d.EzE[dx] * EM1d.Ez[dx]
                  + lass1d.EzH[dx] * (EM1d.Hy[dx] - EM1d.Hy[dx - 1]);
    }

    return EM1d;

}

// Creating loss
Loss createloss2d(Loss lass, double eps, double Cour, double loss){
    for (size_t dx = 0; dx < space; dx++){
        for (size_t dy = 0; dy < space; dy++){
            //if (dx > 100 && dx < 150){
/*
                lass.EzH(dx, dy) = Cour * eps;
                lass.EzE(dx, dy) = 1.0;
                lass.HyH(dx, dy) = 1.0;
                lass.HyE(dx, dy) = Cour / eps;
                lass.HxE(dx, dy) = Cour / eps;
                lass.HxH(dx, dy) = 1.0;
*/

                lass.EzH(dx, dy) =  eps / 9.0 /(1.0 - loss);
                lass.EzE(dx, dy) = (1.0 - loss) / (1.0 + loss);
                lass.HyH(dx, dy) = (1.0 - loss) / (1.0 + loss);
                lass.HyE(dx, dy) = (1.0 / eps) / (1.0 + loss);
                lass.HxE(dx, dy) = (1.0 / eps) / (1.0 + loss);
                lass.HxH(dx, dy) = (1.0 - loss) / (1.0 + loss);
            //}
            /*
            else{
                lass.EzH(dx, dy) =  Cour * eps;
                lass.EzE(dx, dy) = 1.0;
                lass.HyH(dx, dy) = 1.0;
                lass.HyE(dx, dy) = Cour / eps;
                lass.HxE(dx, dy) = Cour / eps;
                lass.HxH(dx, dy) = 1.0;

                lass.EzH(dx, dy) =  eps;
                lass.EzE(dx, dy) = 1.0;
                lass.HyH(dx, dy) = 1.0;
                lass.HyE(dx, dy) = (1.0 / eps);
                lass.HxE(dx, dy) = (1.0 / eps);
                lass.HxH(dx, dy) = 1.0;

            }
            */
        }
    }

    return lass;
}
Loss1d createloss1d(Loss1d lass1d, double eps, double Cour, double loss){
    for (size_t dx = 0; dx < space; dx++){
            //if (dx > 100 && dx < 150){

            lass1d.EzH[dx ]= Cour * eps;
            lass1d.EzE[dx] = 1.0;
            lass1d.HyH[dx] = 1.0;
            lass1d.HyE[dx] = Cour / eps;
/*

            lass1d.EzH[dx] =  eps / 9.0 /(1.0 - loss);
            lass1d.EzE[dx] = (1.0 - loss) / (1.0 + loss);
            lass1d.HyH[dx] = (1.0 - loss) / (1.0 + loss);
*/
            lass1d.HyE[dx] = (1.0 / eps) / (1.0 + loss);
        //}
        /*
        else{
            lass1d.EzH[dx] =  Cour * eps;
            lass1d.EzE[dx] = 1.0;
            lass1d.HyH[dx] = 1.0;
            lass1d.HyE[dx] = Cour / eps;

            lass1d.EzH[dx] =  eps;
            lass1d.EzE[dx] = 1.0;
            lass1d.HyH[dx] = 1.0;
            lass1d.HyE[dx] = (1.0 / eps);

        }
        */
    }

    return lass1d;

}

// TFSF boundaries
Field TFSF(Field EM, Loss lass, Field1d EM1d, Loss1d lass1d, double Cour){
    // TFSF boundary
    Bound first, last;
    first.x = 50; last.x = 150;
    first.y = 50; last.y = 150;

    // Updating along left edge
    int dx = first.x - 1;
    for (int dy = first.y; dy <= last.y; dy++){
        EM.Hy(dx,dy) -= lass.HyE(dx, dy) * EM1d.Ez[dx+1];
    }

    // Update along right edge!
    dx = last.x;
    for (int dy = first.y; dy <= last.y; dy++){
        EM.Hy(dx,dy) += lass.HyE(dx, dy) * EM1d.Ez[dx];
    }

    // Update along bot
    int dy = first.y - 1;
    for (int dx = first.x; dx <= last.x; dx++){
        EM.Hx(dx,dy) += lass.HxE(dx, dy) * EM1d.Ez[dx];
    }

    // Updating along top
    dy = last.y;
    for (int dx = first.x; dx <= last.x; dx++){
        EM.Hx(dx,dy) -= lass.HxE(dx, dy) * EM1d.Ez[dx];
    }

    // Insert 1d grid stuff here. Update magnetic and electric field
    Hupdate1d(EM1d, lass1d, EM.t);
    Eupdate1d(EM1d, lass1d, EM.t);
    EM1d.Ez[100] = ricker(EM.t,0, Cour);
    EM.t++;
    std::cout << EM.t << '\n';

    // Check mag instead of ricker.
    // Updating Ez along left
    dx = first.x;
    for (int dy = first.y; dy <= last.y; dy++){
        EM.Ez(dx, dy) -= lass.EzH(dx, dy) * EM1d.Hy[dx - 1];
    }

    // Update along right
    dx = last.x;
    for (int dy = first.y; dy <= last.y; dy++){
        EM.Ez(dx, dy) += lass.EzH(dx, dy) * EM1d.Hy[dx];
    }

    return EM;

}
<commit_msg>TFSF working!<commit_after>/*-------------FDTD.cpp-------------------------------------------------------//
*
*              Finite Difference Time Domain
*
* Purpose: To replicate the results of our invisible lense raytracer with
*          FDTD. Woo!
*
*   Notes: Most of this is coming from the following link:
*             http://www.eecs.wsu.edu/~schneidj/ufdtd/chap3.pdf
*             http://www.eecs.wsu.edu/~schneidj/ufdtd/chap8.pdf
*
*-----------------------------------------------------------------------------*/

#include <iostream>
#include <vector>
#include <cmath>
#include <fstream>

static const size_t space = 200;

struct Bound{
    int x,y;
};

struct Loss{
    std::vector <double> EzH = std::vector<double>(space * space, 0),
                         EzE = std::vector<double>(space * space, 0),
                         HyE = std::vector<double>(space * space, 0),
                         HyH = std::vector<double>(space * space, 0),
                         HxE = std::vector<double>(space * space, 0),
                         HxH = std::vector<double>(space * space, 0);
};

struct Loss1d{
    std::vector <double> EzH = std::vector<double>(space, 0),
                         EzE = std::vector<double>(space, 0),
                         HyE = std::vector<double>(space, 0),
                         HyH = std::vector<double>(space, 0),
                         HxE = std::vector<double>(space, 0),
                         HxH = std::vector<double>(space, 0);
};

struct Field{
    std::vector <double> Hx = std::vector<double>(space * space, 0),
                         Hy = std::vector<double>(space * space, 0),
                         Ez = std::vector<double>(space * space, 0);

    std::vector <double> Hy1d = std::vector<double>(space, 0),
                         Ez1d = std::vector<double>(space, 0);

    int t;
};

#define EzH(i, j) EzH[(i) + (j) *  space]
#define EzE(i, j) EzE[(i) + (j) *  space]
#define HyH(i, j) HyH[(i) + (j) *  space]
#define HyE(i, j) HyE[(i) + (j) *  space]
#define HxH(i, j) HxH[(i) + (j) *  space]
#define HxE(i, j) HxE[(i) + (j) *  space]
#define Hx(i, j) Hx[(i) + (j) *  space]
#define Hy(i, j) Hy[(i) + (j) *  space]
#define Ez(i, j) Ez[(i) + (j) *  space]

void FDTD(Field EM,
          const int final_time, const double eps, const int space,
          std::ofstream& output);

// Adding ricker solutuion
double ricker(int time, int loc, double Cour);

// 2 dimensional functions for E / H movement
Field Hupdate2d(Field EM, Loss lass, int t);
Field Eupdate2d(Field EM, Loss lass, int t);

// 1 dimensional update functions for E / H
Field Hupdate1d(Field EM, Loss lass, int t);
Field Eupdate1d(Field EM, Loss lass, int t);

// Creating loss
Loss createloss2d(Loss lass, double eps, double Cour, double loss);
Loss1d createloss1d(Loss1d lass1d, double eps, double Cour, double loss);

// TFSF boundaries
Field TFSF(Field EM, Loss lass, Loss1d lass1d, double Cour);

/*----------------------------------------------------------------------------//
* MAIN
*-----------------------------------------------------------------------------*/

int main(){

    // defines output
    std::ofstream output("FDTD.dat", std::ofstream::out);

    int final_time = 1000;
    double eps = 377.0;

    // define initial E and H fields
    // std::vector<double> Ez(space, 0.0), Hy(space, 0.0);
    Field EM;
    EM.t = 0;

    FDTD(EM, final_time, eps, space, output);

}

/*----------------------------------------------------------------------------//
* SUBROUTINES
*-----------------------------------------------------------------------------*/

// This is the function we writs the bulk of the code in
void FDTD(Field EM,
          const int final_time, const double eps, const int space,
          std::ofstream& output){

    // For magnetic field:
    // double offset = 0.00005;

    // for electric field:
    //double offset = 0.05;
    double loss = 0.0;
    double Cour = 1.0 / sqrt(2.0);

    Loss lass;
    lass  = createloss2d(lass, eps, Cour, loss);
    Loss1d lass1d;
    lass1d = createloss1d(lass1d, eps, Cour, loss);

    // Time looping
    for (int t = 0; t < final_time; t++){

        EM = Hupdate2d(EM, lass, t);
        EM = TFSF(EM, lass, lass1d, Cour);
        EM = Eupdate2d(EM,lass,t);
        //EM.Ez(0,100) = ricker(t, 0, Cour);

        // Outputting to a file
        int check = 5;
        if (t % check == 0){
            for (int dx = 0; dx < space; dx = dx + check){
                for (int dy = 0; dy < space; dy = dy + check){
                    output << t << '\t' << dx <<'\t' << dy << '\t'
                           << EM.Ez(dx, dy) << '\t' << EM.Hy(dx, dy)
                           << '\t' << EM.Hx(dx, dy) << '\t' << '\n';
                    //output << Ez(dx,dy) + (t * offset) << '\n';
                    //output << Hy[dx] + (t * offset) << '\n';
                }
            }

            output << '\n' << '\n';
        }

    }
}

// Adding the ricker solution
double ricker(int time, int loc, double Cour){
    double Ricky;
    double temp_const = 3.14159*((Cour*(double)time - (double)loc)/20.0 - 1.0);
    temp_const = temp_const * temp_const;
    Ricky = (1.0 - 2.0 * temp_const) * exp(-temp_const);
    return Ricky;

}

// 2 dimensional functions for E / H movement
Field Hupdate2d(Field EM, Loss lass, int t){
    // update magnetic field, x direction
    for (size_t dx = 0; dx < space; dx++){
        for (size_t dy = 0; dy < space - 1; dy++){
           EM.Hx(dx,dy) = lass.HxH(dx,dy) * EM.Hx(dx, dy)
                       - lass.HxE(dx,dy) * (EM.Ez(dx,dy + 1)
                                            - EM.Ez(dx,dy));
        }
    }

    // update magnetic field, y direction
    for (size_t dx = 0; dx < space - 1; dx++){
        for (size_t dy = 0; dy < space; dy++){
           EM.Hy(dx,dy) = lass.HyH(dx,dy) * EM.Hy(dx,dy)
                      + lass.HyE(dx,dy) * (EM.Ez(dx + 1,dy)
                                            - EM.Ez(dx,dy));
        }
    }

    return EM;

}

Field Eupdate2d(Field EM, Loss lass, int t){
    // update electric field
    for (size_t dx = 1; dx < space - 1; dx++){
        for (size_t dy = 1; dy < space - 1; dy++){
           EM.Ez(dx,dy) = lass.EzE(dx,dy) * EM.Ez(dx,dy)
                       + lass.EzH(dx,dy) * ((EM.Hy(dx, dy)
                                         - EM.Hy(dx - 1, dy))
                                         - (EM.Hx(dx,dy)
                                         - EM.Hx(dx, dy - 1)));
        }
    }
    return EM;
}

// 1 dimensional update functions for E / H
Field Hupdate1d(Field EM, Loss1d lass1d, int t){
    // update magnetic field, y direction
    for (size_t dx = 0; dx < space - 1; dx++){
        EM.Hy1d[dx] = lass1d.HyH[dx] * EM.Hy1d[dx]
                  + lass1d.HyE[dx] * (EM.Ez1d[dx + 1] - EM.Ez1d[dx]);
    }

    return EM;
}

Field Eupdate1d(Field EM, Loss1d lass1d, int t){
    // update electric field, y direction
    for (size_t dx = 1; dx < space - 1; dx++){
        EM.Ez1d[dx] = lass1d.EzE[dx] * EM.Ez1d[dx]
                  + lass1d.EzH[dx] * (EM.Hy1d[dx] - EM.Hy1d[dx - 1]);
    }

    return EM;

}

// Creating loss
Loss createloss2d(Loss lass, double eps, double Cour, double loss){
    for (size_t dx = 0; dx < space; dx++){
        for (size_t dy = 0; dy < space; dy++){
            //if (dx > 100 && dx < 150){
/*
                lass.EzH(dx, dy) = Cour * eps;
                lass.EzE(dx, dy) = 1.0;
                lass.HyH(dx, dy) = 1.0;
                lass.HyE(dx, dy) = Cour / eps;
                lass.HxE(dx, dy) = Cour / eps;
                lass.HxH(dx, dy) = 1.0;
*/

                lass.EzH(dx, dy) =  eps / 9.0 /(1.0 - loss);
                lass.EzE(dx, dy) = (1.0 - loss) / (1.0 + loss);
                lass.HyH(dx, dy) = (1.0 - loss) / (1.0 + loss);
                lass.HyE(dx, dy) = (1.0 / eps) / (1.0 + loss);
                lass.HxE(dx, dy) = (1.0 / eps) / (1.0 + loss);
                lass.HxH(dx, dy) = (1.0 - loss) / (1.0 + loss);
            //}
            /*
            else{
                lass.EzH(dx, dy) =  Cour * eps;
                lass.EzE(dx, dy) = 1.0;
                lass.HyH(dx, dy) = 1.0;
                lass.HyE(dx, dy) = Cour / eps;
                lass.HxE(dx, dy) = Cour / eps;
                lass.HxH(dx, dy) = 1.0;

                lass.EzH(dx, dy) =  eps;
                lass.EzE(dx, dy) = 1.0;
                lass.HyH(dx, dy) = 1.0;
                lass.HyE(dx, dy) = (1.0 / eps);
                lass.HxE(dx, dy) = (1.0 / eps);
                lass.HxH(dx, dy) = 1.0;

            }
            */
        }
    }

    return lass;
}
Loss1d createloss1d(Loss1d lass1d, double eps, double Cour, double loss){
    for (size_t dx = 0; dx < space; dx++){
            //if (dx > 100 && dx < 150){

            lass1d.EzH[dx ]= Cour * eps;
            lass1d.EzE[dx] = 1.0;
            lass1d.HyH[dx] = 1.0;
            lass1d.HyE[dx] = Cour / eps;
/*

            lass1d.EzH[dx] =  eps / 9.0 /(1.0 - loss);
            lass1d.EzE[dx] = (1.0 - loss) / (1.0 + loss);
            lass1d.HyH[dx] = (1.0 - loss) / (1.0 + loss);
*/
            lass1d.HyE[dx] = (1.0 / eps) / (1.0 + loss);
        //}
        /*
        else{
            lass1d.EzH[dx] =  Cour * eps;
            lass1d.EzE[dx] = 1.0;
            lass1d.HyH[dx] = 1.0;
            lass1d.HyE[dx] = Cour / eps;

            lass1d.EzH[dx] =  eps;
            lass1d.EzE[dx] = 1.0;
            lass1d.HyH[dx] = 1.0;
            lass1d.HyE[dx] = (1.0 / eps);

        }
        */
    }

    return lass1d;

}

// TFSF boundaries
Field TFSF(Field EM, Loss lass, Loss1d lass1d, double Cour){
    // TFSF boundary
    Bound first, last;
    first.x = 50; last.x = 150;
    first.y = 50; last.y = 150;

    // Updating along left edge
    int dx = first.x - 1;
    for (int dy = first.y; dy <= last.y; dy++){
        EM.Hy(dx,dy) -= lass.HyE(dx, dy) * EM.Ez1d[dx+1];
    }

    // Update along right edge!
    dx = last.x;
    for (int dy = first.y; dy <= last.y; dy++){
        EM.Hy(dx,dy) += lass.HyE(dx, dy) * EM.Ez1d[dx];
    }

    // Update along bot
    int dy = first.y - 1;
    for (int dx = first.x; dx <= last.x; dx++){
        EM.Hx(dx,dy) += lass.HxE(dx, dy) * EM.Ez1d[dx];
    }

    // Updating along top
    dy = last.y;
    for (int dx = first.x; dx <= last.x; dx++){
        EM.Hx(dx,dy) -= lass.HxE(dx, dy) * EM.Ez1d[dx];
    }

    // Insert 1d grid stuff here. Update magnetic and electric field
    Hupdate1d(EM, lass1d, EM.t);
    Eupdate1d(EM, lass1d, EM.t);
    EM.Ez1d[50] = ricker(EM.t,0, Cour);
    EM.t++;
    std::cout << EM.t << '\n';

    // Check mag instead of ricker.
    // Updating Ez along left
    dx = first.x;
    for (int dy = first.y; dy <= last.y; dy++){
        EM.Ez(dx, dy) -= lass.EzH(dx, dy) * EM.Hy1d[dx - 1];
    }

    // Update along right
    dx = last.x;
    for (int dy = first.y; dy <= last.y; dy++){
        EM.Ez(dx, dy) += lass.EzH(dx, dy) * EM.Hy1d[dx];
    }

    return EM;

}
<|endoftext|>


<commit_before>/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2015 Hugo Beauzée-Luyssen, Videolabs
 *
 * Authors: Hugo Beauzée-Luyssen<hugo@beauzee.fr>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#include "File.h"

#include "Media.h"
#include "Folder.h"

const std::string policy::FileTable::Name = "File";
const std::string policy::FileTable::PrimaryKeyColumn = "id_file";
unsigned int File::* const policy::FileTable::PrimaryKey = &File::m_id;

File::File( DBConnection dbConnection, sqlite::Row& row )
    : m_dbConnection( dbConnection )
{
    row >> m_id
        >> m_mediaId
        >> m_mrl
        >> m_type
        >> m_lastModificationDate
        >> m_isParsed
        >> m_folderId
        >> m_isPresent
        >> m_isRemovable;
}

File::File( unsigned int mediaId, Type type, const fs::IFile& file, unsigned int folderId, bool isRemovable )
    : m_id( 0 )
    , m_mediaId( mediaId )
    , m_mrl( isRemovable == true ? file.name() : file.fullPath() )
    , m_type( type )
    , m_lastModificationDate( file.lastModificationDate() )
    , m_isParsed( false )
    , m_folderId( folderId )
    , m_isPresent( true )
    , m_isRemovable( isRemovable )
{
}

unsigned int File::id() const
{
    return m_id;
}

const std::string& File::mrl() const
{
    if ( m_isRemovable == false )
        return m_mrl;

    auto lock = m_fullPath.lock();
    if ( m_fullPath.isCached() )
        return m_fullPath;
    auto folder = Folder::fetch( m_dbConnection, m_folderId );
    if ( folder == nullptr )
        return m_mrl;
    m_fullPath = folder->path() + m_mrl;
    return m_fullPath;
}

IFile::Type File::type() const
{
    return m_type;
}

unsigned int File::lastModificationDate() const
{
    return m_lastModificationDate;
}

bool File::isParsed() const
{
    return m_isParsed;
}

std::shared_ptr<Media> File::media() const
{
    auto lock = m_media.lock();
    if ( m_media.isCached() == false )
    {
        m_media = Media::fetch( m_dbConnection, m_mediaId );
    }
    return m_media.get().lock();
}

bool File::destroy()
{
    return DatabaseHelpers::destroy( m_dbConnection, m_id );
}

void File::markParsed()
{
    if ( m_isParsed == true )
        return;
    static const std::string req = "UPDATE " + policy::FileTable::Name + " SET parsed = 1 WHERE id_file = ?";
    if ( sqlite::Tools::executeUpdate( m_dbConnection, req, m_id ) == false )
        return;
    m_isParsed = true;
}

bool File::createTable( DBConnection dbConnection )
{
    std::string req = "CREATE TABLE IF NOT EXISTS " + policy::FileTable::Name + "("
            "id_file INTEGER PRIMARY KEY AUTOINCREMENT,"
            "media_id INT NOT NULL,"
            "mrl TEXT,"
            "type UNSIGNED INTEGER,"
            "last_modification_date UNSIGNED INT,"
            "parsed BOOLEAN NOT NULL DEFAULT 0,"
            "folder_id UNSIGNED INTEGER,"
            "is_present BOOLEAN NOT NULL DEFAULT 1,"
            "is_removable BOOLEAN NOT NULL,"
            "FOREIGN KEY (media_id) REFERENCES " + policy::MediaTable::Name
            + "(id_media) ON DELETE CASCADE,"
            "FOREIGN KEY (folder_id) REFERENCES " + policy::FolderTable::Name
            + "(id_folder) ON DELETE CASCADE,"
            "UNIQUE( mrl, folder_id ) ON CONFLICT FAIL"
        ")";
    std::string triggerReq = "CREATE TRIGGER IF NOT EXISTS is_folder_present AFTER UPDATE OF is_present ON "
            + policy::FolderTable::Name +
            " BEGIN"
            " UPDATE " + policy::FileTable::Name + " SET is_present = new.is_present WHERE folder_id = new.id_folder;"
            " END";
    return sqlite::Tools::executeRequest( dbConnection, req ) &&
            sqlite::Tools::executeRequest( dbConnection, triggerReq );
}

std::shared_ptr<File> File::create( DBConnection dbConnection, unsigned int mediaId, Type type, const fs::IFile& fileFs, unsigned int folderId, bool isRemovable )
{
    auto self = std::make_shared<File>( mediaId, type, fileFs, folderId, isRemovable );
    static const std::string req = "INSERT INTO " + policy::FileTable::Name +
            "(media_id, mrl, type, folder_id, last_modification_date, is_removable) VALUES(?, ?, ?, ?, ?, ?)";

    if ( insert( dbConnection, self, req, mediaId, self->m_mrl, type, sqlite::ForeignKey( folderId ),
                         self->m_lastModificationDate, isRemovable ) == false )
        return nullptr;
    self->m_dbConnection = dbConnection;
    self->m_fullPath = fileFs.fullPath();
    return self;
}
<commit_msg>File: Index media_id<commit_after>/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2015 Hugo Beauzée-Luyssen, Videolabs
 *
 * Authors: Hugo Beauzée-Luyssen<hugo@beauzee.fr>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#include "File.h"

#include "Media.h"
#include "Folder.h"

const std::string policy::FileTable::Name = "File";
const std::string policy::FileTable::PrimaryKeyColumn = "id_file";
unsigned int File::* const policy::FileTable::PrimaryKey = &File::m_id;

File::File( DBConnection dbConnection, sqlite::Row& row )
    : m_dbConnection( dbConnection )
{
    row >> m_id
        >> m_mediaId
        >> m_mrl
        >> m_type
        >> m_lastModificationDate
        >> m_isParsed
        >> m_folderId
        >> m_isPresent
        >> m_isRemovable;
}

File::File( unsigned int mediaId, Type type, const fs::IFile& file, unsigned int folderId, bool isRemovable )
    : m_id( 0 )
    , m_mediaId( mediaId )
    , m_mrl( isRemovable == true ? file.name() : file.fullPath() )
    , m_type( type )
    , m_lastModificationDate( file.lastModificationDate() )
    , m_isParsed( false )
    , m_folderId( folderId )
    , m_isPresent( true )
    , m_isRemovable( isRemovable )
{
}

unsigned int File::id() const
{
    return m_id;
}

const std::string& File::mrl() const
{
    if ( m_isRemovable == false )
        return m_mrl;

    auto lock = m_fullPath.lock();
    if ( m_fullPath.isCached() )
        return m_fullPath;
    auto folder = Folder::fetch( m_dbConnection, m_folderId );
    if ( folder == nullptr )
        return m_mrl;
    m_fullPath = folder->path() + m_mrl;
    return m_fullPath;
}

IFile::Type File::type() const
{
    return m_type;
}

unsigned int File::lastModificationDate() const
{
    return m_lastModificationDate;
}

bool File::isParsed() const
{
    return m_isParsed;
}

std::shared_ptr<Media> File::media() const
{
    auto lock = m_media.lock();
    if ( m_media.isCached() == false )
    {
        m_media = Media::fetch( m_dbConnection, m_mediaId );
    }
    return m_media.get().lock();
}

bool File::destroy()
{
    return DatabaseHelpers::destroy( m_dbConnection, m_id );
}

void File::markParsed()
{
    if ( m_isParsed == true )
        return;
    static const std::string req = "UPDATE " + policy::FileTable::Name + " SET parsed = 1 WHERE id_file = ?";
    if ( sqlite::Tools::executeUpdate( m_dbConnection, req, m_id ) == false )
        return;
    m_isParsed = true;
}

bool File::createTable( DBConnection dbConnection )
{
    std::string req = "CREATE TABLE IF NOT EXISTS " + policy::FileTable::Name + "("
            "id_file INTEGER PRIMARY KEY AUTOINCREMENT,"
            "media_id INT NOT NULL,"
            "mrl TEXT,"
            "type UNSIGNED INTEGER,"
            "last_modification_date UNSIGNED INT,"
            "parsed BOOLEAN NOT NULL DEFAULT 0,"
            "folder_id UNSIGNED INTEGER,"
            "is_present BOOLEAN NOT NULL DEFAULT 1,"
            "is_removable BOOLEAN NOT NULL,"
            "FOREIGN KEY (media_id) REFERENCES " + policy::MediaTable::Name
            + "(id_media) ON DELETE CASCADE,"
            "FOREIGN KEY (folder_id) REFERENCES " + policy::FolderTable::Name
            + "(id_folder) ON DELETE CASCADE,"
            "UNIQUE( mrl, folder_id ) ON CONFLICT FAIL"
        ")";
    std::string triggerReq = "CREATE TRIGGER IF NOT EXISTS is_folder_present AFTER UPDATE OF is_present ON "
            + policy::FolderTable::Name +
            " BEGIN"
            " UPDATE " + policy::FileTable::Name + " SET is_present = new.is_present WHERE folder_id = new.id_folder;"
            " END";
    std::string indexReq = "CREATE INDEX IF NOT EXISTS file_media_id_index ON " +
            policy::FileTable::Name + "(media_id)";
    return sqlite::Tools::executeRequest( dbConnection, req ) &&
            sqlite::Tools::executeRequest( dbConnection, triggerReq ) &&
            sqlite::Tools::executeRequest( dbConnection, indexReq );
}

std::shared_ptr<File> File::create( DBConnection dbConnection, unsigned int mediaId, Type type, const fs::IFile& fileFs, unsigned int folderId, bool isRemovable )
{
    auto self = std::make_shared<File>( mediaId, type, fileFs, folderId, isRemovable );
    static const std::string req = "INSERT INTO " + policy::FileTable::Name +
            "(media_id, mrl, type, folder_id, last_modification_date, is_removable) VALUES(?, ?, ?, ?, ?, ?)";

    if ( insert( dbConnection, self, req, mediaId, self->m_mrl, type, sqlite::ForeignKey( folderId ),
                         self->m_lastModificationDate, isRemovable ) == false )
        return nullptr;
    self->m_dbConnection = dbConnection;
    self->m_fullPath = fileFs.fullPath();
    return self;
}
<|endoftext|>