<commit_before>/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.

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. */

#include "paddle/fluid/inference/analysis/subgraph_splitter.h"

namespace paddle {
namespace inference {
namespace analysis {

const char *SubGraphSplitter::kMarkerAttrName =
    "_sub_graph_splitter_inside_sub_graph";

std::vector<std::vector<Node *>> SubGraphSplitter::operator()() {
  MarkNodesInsideSubGraph();
  return ExtractSubGraphs();
}

// Mark the output variables inside a subgraph with the func.
inline void MarkOutLinksInSubGraph(const Function *func) {
  for (auto *var : func->outlinks) {
    var->attr(SubGraphSplitter::kMarkerAttrName).Bool() = true;
  }
}

void SubGraphSplitter::MarkNodesInsideSubGraph() {
  for (auto &node : GraphTraits<DataFlowGraph>(*graph_).nodes()) {
    if (node_inside_subgraph_teller_(&node)) {
      node.attr(kMarkerAttrName).Bool() = true;
      if (node.type() == Node::Type::kFunction) {
        // If a function is inside the sub-graph, mark all the output variables
        // to be inside too, so that two marked functions will be inside a same
        // sub-graph, lets take a example:  A_function->var->B_function, if
        // A_function is marked, var should also be marked, so that B_function
        // will be in the same sub-graph with A_function if B_function is
        // marked.
        MarkOutLinksInSubGraph(static_cast<const Function *>(&node));
      }
    }
  }
}

const char *kUnionFindParent = "_sub_graph_splitter_union_find_parent_";

// Use the Union Find(UF) algorithm to find fully connected sub-graphs, if node
// a's output is node b, that is a and b is in the same sub-graph. The UF
// algorithm will group them to the same cluster.
using node_map_t = std::unordered_map<int, Node *>;
// Find the ancestor id of a node.
int UnionFindGetAncestor(const node_map_t &node_map, size_t id) {
  int tmp = id;
  do {
    tmp = node_map.at(tmp)->attr(kUnionFindParent).Int32();
  } while (node_map.at(tmp)->attr(kUnionFindParent).Int32() != tmp);
  return tmp;
}
// Make this two node share the same ancestor.
// TODO(Superjom) bad performance, make a balanced tree latter.
void UnionFindCombine(const node_map_t &node_map, size_t a, size_t b) {
  int a_ancestor = UnionFindGetAncestor(node_map, a);
  int b_ancestor = UnionFindGetAncestor(node_map, b);
  node_map.at(b_ancestor)->attr(kUnionFindParent).Int32() = a_ancestor;
  node_map.at(a)->attr(kUnionFindParent).Int32() = a_ancestor;
  node_map.at(b)->attr(kUnionFindParent).Int32() = a_ancestor;
}

// This is a simple representation of a graph.
// The BriefNode hold the pointer of the Node.
// This is to avoid changing the original graph
// in the process of trt graph analysis.
struct BriefNode {
  explicit BriefNode(Node *n) { node = n; }
  Node *node;
  std::vector<BriefNode *> inlinks;
  std::vector<BriefNode *> outlinks;
};

// Union two adjacent BriefNode.
// Suppose we have two adjacent nodes src and dst.
// We will perform the following operations:
// 1. add all inputs(except src) of dst to src inlinks.
// 2. add all outputs of dst to src outlinks.
// 3. change all the dst's inputs and outputs
// corresponding inlinks and outlinks to src node.
// 4. delete all dst's inlinks and outlinks.
void UnionContractedNodes(const std::unordered_map<int, BriefNode *> &node_map,
                          int src_id, int dst_id) {
  // merge the two adjacent nodes into one node.
  BriefNode *src_node = node_map.at(src_id);
  BriefNode *dst_node = node_map.at(dst_id);

  std::unordered_set<BriefNode *> inputs(src_node->inlinks.begin(),
                                         src_node->inlinks.end());
  std::unordered_set<BriefNode *> outputs;

  for (auto *n : src_node->outlinks) {
    if (n != dst_node) outputs.insert(n);
  }

  // Add the inlinks and outlinks of dst node to src node.
  std::vector<BriefNode *> dst_in_nodes = dst_node->inlinks;
  for (BriefNode *node : dst_in_nodes) {
    if (node != src_node) {
      inputs.insert(node);
    }
  }

  std::vector<BriefNode *> dst_out_nodes = dst_node->outlinks;
  for (BriefNode *node : dst_out_nodes) {
    outputs.insert(node);
  }

  // update the dst and src node's inlinks and outlinks.
  src_node->inlinks =
      std::move(std::vector<BriefNode *>(inputs.begin(), inputs.end()));
  src_node->outlinks =
      std::move(std::vector<BriefNode *>(outputs.begin(), outputs.end()));
  dst_node->inlinks.clear();
  dst_node->outlinks.clear();

  auto inlink_or_outlink_cleaner = [&](std::vector<BriefNode *> &nodes) {
    for (auto *&n : nodes) {
      if (n == src_node || n == dst_node) {
        n = src_node;
      }
    }
  };
  // Change all the dst inputs and outputs corresponding inlink and
  // outlink to the src node.
  for (auto *node : src_node->inlinks) {
    inlink_or_outlink_cleaner(node->outlinks);
  }

  for (auto *node : src_node->outlinks) {
    inlink_or_outlink_cleaner(node->inlinks);
  }
}

// FlexibleDFS
// If reverse is true, do reverse dfs.
// If enter func is not nullptr, calls enter(node) before visiting any children
// of node.
// If leave func not nullptr, calls leave(node) after visiting all parents of
// node.
void FlexibleDFS(const std::vector<BriefNode *> &source, bool reverse,
                 const std::function<bool(const BriefNode *)> &enter,
                 const std::function<bool(const BriefNode *)> &leave) {
  typedef struct {
    const BriefNode *node;
    bool leave;
  } FNode;

  std::vector<FNode> stack;
  for (auto &node : source) {
    stack.push_back(FNode{node, false});
  }
  std::unordered_set<const BriefNode *> visited;
  while (!stack.empty()) {
    auto fnode = stack.back();
    stack.pop_back();

    if (fnode.leave) {
      if (leave && !leave(fnode.node)) return;
    }
    if (visited.count(fnode.node)) continue;
    visited.insert(fnode.node);

    if (enter && !enter(fnode.node)) return;

    if (leave) stack.push_back(FNode{fnode.node, true});
    const std::vector<BriefNode *> iter_nodes =
        reverse == true ? fnode.node->inlinks : fnode.node->outlinks;
    for (const BriefNode *node : iter_nodes) {
      if (!visited.count(node)) {
        stack.push_back(FNode{node, false});
      }
    }
  }
}

std::vector<std::vector<Node *>> SubGraphSplitter::ExtractSubGraphs() {
  // Run the Extract algorithm to find all subgraphs.
  std::vector<Node *> marked_nodes;
  //  We use brief_node_map to represent the original graph in order to avoid
  //  changing the original graph.
  std::unordered_map<int, BriefNode *> brief_node_map;

  for (auto &node : GraphTraits<DataFlowGraph>(*graph_).nodes_in_TS()) {
    brief_node_map[node.id()] = new BriefNode(&node);
    if (node.attr(kMarkerAttrName).Bool()) {
      marked_nodes.push_back(&node);
    }
  }

  // extract sub-graphs in the marked node set, use Union Find algorithm.
  node_map_t node_map;  // id to ptr
  for (auto *n : marked_nodes) {
    // n's parent == n.id means it is the ancestor
    n->attr(kUnionFindParent).Int32() = n->id();
    node_map[n->id()] = n;
  }

  // create breif node map
  for (auto &itr : brief_node_map) {
    for (Node *node : itr.second->node->inlinks) {
      itr.second->inlinks.push_back(brief_node_map[node->id()]);
    }

    for (Node *node : itr.second->node->outlinks) {
      itr.second->outlinks.push_back(brief_node_map[node->id()]);
    }
  }

  for (auto &itr : brief_node_map) {
    BriefNode *brief_node = itr.second;

    if (!brief_node->node->attr(kMarkerAttrName).Bool()) {
      VLOG(4) << brief_node->node->id() << " node not a trt candicate.";
      continue;
    }

    //  Our algorithm must guarantee that:
    //  1. The graph is always directed acyclic graph（DAG）.
    //  2. If there is a path in the subgraph from X to Y (X and Y are both
    //  nodes in the subgraph), then all paths from X to Y are in the
    //  subgraph.
    //
    //  In order to achieve the above guarantee.
    //  For adjacent nodes src -> dst.
    //  1. Get all dst input nodes except src.
    //  2. Reverse DFS from those input nodes
    //  3. If there is a path from input nodes to src,
    //  then the src and dst nodes can not be fused into one node,
    //  otherwise it can be done.

    while (true) {
      std::unordered_set<BriefNode *> contract_nodes;
      for (auto *out : brief_node->outlinks) {
        // must be an trt candidate
        if (!out->node->attr(kMarkerAttrName).Bool()) continue;
        // get all dst input nodes except src.
        std::vector<BriefNode *> source_nodes;
        for (auto *n : out->inlinks) {
          if (n != brief_node) {
            source_nodes.push_back(n);
          }
        }

        // Reverse DFS from the source_nodes.
        bool have_excess_path = false;
        FlexibleDFS(source_nodes, true, nullptr,
                    [&have_excess_path, brief_node](const BriefNode *n) {
                      if (n == brief_node) {
                        have_excess_path = true;
                        return false;
                      }
                      return true;
                    });
        if (have_excess_path) continue;
        contract_nodes.insert(out);
      }
      if (contract_nodes.empty()) break;

      for (auto dst_node : contract_nodes) {
        UnionFindCombine(node_map, brief_node->node->id(),
                         dst_node->node->id());
        UnionContractedNodes(brief_node_map, brief_node->node->id(),
                             dst_node->node->id());
      }
    }
  }

  std::unordered_map<int /*ancestor*/, std::vector<Node *>> clusters;
  for (auto *n : marked_nodes) {
    if (n->type() == Node::Type::kFunction) {
      clusters[UnionFindGetAncestor(node_map,
                                    n->attr(kUnionFindParent).Int32())]
          .push_back(n);
    }
  }
  std::vector<std::vector<Node *>> result;
  std::for_each(clusters.begin(), clusters.end(),
                [&](const decltype(clusters)::value_type &it) {
                  result.push_back(it.second);
                });

  return result;
}

void SubGraphFuse::operator()() { ReplaceNodesWithSubGraphs(); }

void SubGraphFuse::ReplaceNodesWithSubGraphs() {
  auto subgraphs = SubGraphSplitter(graph_, node_inside_subgraph_teller_)();
  for (auto &subgraph : subgraphs) {
    std::unordered_set<Node *> subgraph_uniq(subgraph.begin(), subgraph.end());
    // replace this sub-graph with the first node. Two steps: 1. Create a Block
    // Node that contains this subgraph 2. Mark the nodes inside the sub-graph
    // as deleted. 3. Replace the deleted node with the new Block Node.
    auto *block_node = static_cast<FunctionBlock *>(
        graph_->nodes.Create(Node::Type::kFunctionBlock));
    auto io = ExtractInputAndOutputOfSubGraph(subgraph);
    block_node->inlinks = std::move(io.first);
    block_node->outlinks = std::move(io.second);

    for (auto *node : subgraph) {
      // TODO(Superjomn) need a unified mechanism to treat deleted node in each
      // pass.
      node->SetDeleted();
      block_node->subgraph.push_back(node);
    }

    // Change all the sub-graph's inputs and outputs corresponding inlink and
    // outlink to this sub-graph node.
    auto inlink_or_outlink_cleaner = [&](std::vector<Node *> &nodes) {
      for (auto *&n : nodes) {
        if (subgraph_uniq.count(n)) {
          n = block_node;
        }
      }
      std::unordered_set<Node *> uniq(nodes.begin(), nodes.end());
      nodes.assign(uniq.begin(), uniq.end());
    };
    for (auto *i : block_node->inlinks) {
      inlink_or_outlink_cleaner(i->outlinks);
    }
    for (auto *&o : block_node->outlinks) {
      inlink_or_outlink_cleaner(o->inlinks);
    }
  }
  FilterRedundantOutputOfSubGraph(graph_);
}

}  // namespace analysis
}  // namespace inference
}  // namespace paddle
<commit_msg>fix mac compile error in subgraph_splitter<commit_after>/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.

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. */

#include "paddle/fluid/inference/analysis/subgraph_splitter.h"

namespace paddle {
namespace inference {
namespace analysis {

const char *SubGraphSplitter::kMarkerAttrName =
    "_sub_graph_splitter_inside_sub_graph";

std::vector<std::vector<Node *>> SubGraphSplitter::operator()() {
  MarkNodesInsideSubGraph();
  return ExtractSubGraphs();
}

// Mark the output variables inside a subgraph with the func.
inline void MarkOutLinksInSubGraph(const Function *func) {
  for (auto *var : func->outlinks) {
    var->attr(SubGraphSplitter::kMarkerAttrName).Bool() = true;
  }
}

void SubGraphSplitter::MarkNodesInsideSubGraph() {
  for (auto &node : GraphTraits<DataFlowGraph>(*graph_).nodes()) {
    if (node_inside_subgraph_teller_(&node)) {
      node.attr(kMarkerAttrName).Bool() = true;
      if (node.type() == Node::Type::kFunction) {
        // If a function is inside the sub-graph, mark all the output variables
        // to be inside too, so that two marked functions will be inside a same
        // sub-graph, lets take a example:  A_function->var->B_function, if
        // A_function is marked, var should also be marked, so that B_function
        // will be in the same sub-graph with A_function if B_function is
        // marked.
        MarkOutLinksInSubGraph(static_cast<const Function *>(&node));
      }
    }
  }
}

const char *kUnionFindParent = "_sub_graph_splitter_union_find_parent_";

// Use the Union Find(UF) algorithm to find fully connected sub-graphs, if node
// a's output is node b, that is a and b is in the same sub-graph. The UF
// algorithm will group them to the same cluster.
using node_map_t = std::unordered_map<int, Node *>;
// Find the ancestor id of a node.
int UnionFindGetAncestor(const node_map_t &node_map, size_t id) {
  int tmp = id;
  do {
    tmp = node_map.at(tmp)->attr(kUnionFindParent).Int32();
  } while (node_map.at(tmp)->attr(kUnionFindParent).Int32() != tmp);
  return tmp;
}
// Make this two node share the same ancestor.
// TODO(Superjom) bad performance, make a balanced tree latter.
void UnionFindCombine(const node_map_t &node_map, size_t a, size_t b) {
  int a_ancestor = UnionFindGetAncestor(node_map, a);
  int b_ancestor = UnionFindGetAncestor(node_map, b);
  node_map.at(b_ancestor)->attr(kUnionFindParent).Int32() = a_ancestor;
  node_map.at(a)->attr(kUnionFindParent).Int32() = a_ancestor;
  node_map.at(b)->attr(kUnionFindParent).Int32() = a_ancestor;
}

// This is a simple representation of a graph.
// The BriefNode hold the pointer of the Node.
// This is to avoid changing the original graph
// in the process of trt graph analysis.
struct BriefNode {
  explicit BriefNode(Node *n) { node = n; }
  Node *node;
  std::vector<BriefNode *> inlinks;
  std::vector<BriefNode *> outlinks;
};

// Union two adjacent BriefNode.
// Suppose we have two adjacent nodes src and dst.
// We will perform the following operations:
// 1. add all inputs(except src) of dst to src inlinks.
// 2. add all outputs of dst to src outlinks.
// 3. change all the dst's inputs and outputs
// corresponding inlinks and outlinks to src node.
// 4. delete all dst's inlinks and outlinks.
void UnionContractedNodes(const std::unordered_map<int, BriefNode *> &node_map,
                          int src_id, int dst_id) {
  // merge the two adjacent nodes into one node.
  BriefNode *src_node = node_map.at(src_id);
  BriefNode *dst_node = node_map.at(dst_id);

  std::unordered_set<BriefNode *> inputs(src_node->inlinks.begin(),
                                         src_node->inlinks.end());
  std::unordered_set<BriefNode *> outputs;

  for (auto *n : src_node->outlinks) {
    if (n != dst_node) outputs.insert(n);
  }

  // Add the inlinks and outlinks of dst node to src node.
  std::vector<BriefNode *> dst_in_nodes = dst_node->inlinks;
  for (BriefNode *node : dst_in_nodes) {
    if (node != src_node) {
      inputs.insert(node);
    }
  }

  std::vector<BriefNode *> dst_out_nodes = dst_node->outlinks;
  for (BriefNode *node : dst_out_nodes) {
    outputs.insert(node);
  }

// update the dst and src node's inlinks and outlinks.
#ifdef __clang__
  src_node->inlinks = std::vector<BriefNode *>(inputs.begin(), inputs.end());
  src_node->outlinks = std::vector<BriefNode *>(outputs.begin(), outputs.end());
  dst_node->inlinks.clear();
  dst_node->outlinks.clear();
#else
  src_node->inlinks =
      std::move(std::vector<BriefNode *>(inputs.begin(), inputs.end()));
  src_node->outlinks =
      std::move(std::vector<BriefNode *>(outputs.begin(), outputs.end()));
  dst_node->inlinks.clear();
  dst_node->outlinks.clear();
#endif

  auto inlink_or_outlink_cleaner = [&](std::vector<BriefNode *> &nodes) {
    for (auto *&n : nodes) {
      if (n == src_node || n == dst_node) {
        n = src_node;
      }
    }
  };
  // Change all the dst inputs and outputs corresponding inlink and
  // outlink to the src node.
  for (auto *node : src_node->inlinks) {
    inlink_or_outlink_cleaner(node->outlinks);
  }

  for (auto *node : src_node->outlinks) {
    inlink_or_outlink_cleaner(node->inlinks);
  }
}

// FlexibleDFS
// If reverse is true, do reverse dfs.
// If enter func is not nullptr, calls enter(node) before visiting any children
// of node.
// If leave func not nullptr, calls leave(node) after visiting all parents of
// node.
void FlexibleDFS(const std::vector<BriefNode *> &source, bool reverse,
                 const std::function<bool(const BriefNode *)> &enter,
                 const std::function<bool(const BriefNode *)> &leave) {
  typedef struct {
    const BriefNode *node;
    bool leave;
  } FNode;

  std::vector<FNode> stack;
  for (auto &node : source) {
    stack.push_back(FNode{node, false});
  }
  std::unordered_set<const BriefNode *> visited;
  while (!stack.empty()) {
    auto fnode = stack.back();
    stack.pop_back();

    if (fnode.leave) {
      if (leave && !leave(fnode.node)) return;
    }
    if (visited.count(fnode.node)) continue;
    visited.insert(fnode.node);

    if (enter && !enter(fnode.node)) return;

    if (leave) stack.push_back(FNode{fnode.node, true});
    const std::vector<BriefNode *> iter_nodes =
        reverse == true ? fnode.node->inlinks : fnode.node->outlinks;
    for (const BriefNode *node : iter_nodes) {
      if (!visited.count(node)) {
        stack.push_back(FNode{node, false});
      }
    }
  }
}

std::vector<std::vector<Node *>> SubGraphSplitter::ExtractSubGraphs() {
  // Run the Extract algorithm to find all subgraphs.
  std::vector<Node *> marked_nodes;
  //  We use brief_node_map to represent the original graph in order to avoid
  //  changing the original graph.
  std::unordered_map<int, BriefNode *> brief_node_map;

  for (auto &node : GraphTraits<DataFlowGraph>(*graph_).nodes_in_TS()) {
    brief_node_map[node.id()] = new BriefNode(&node);
    if (node.attr(kMarkerAttrName).Bool()) {
      marked_nodes.push_back(&node);
    }
  }

  // extract sub-graphs in the marked node set, use Union Find algorithm.
  node_map_t node_map;  // id to ptr
  for (auto *n : marked_nodes) {
    // n's parent == n.id means it is the ancestor
    n->attr(kUnionFindParent).Int32() = n->id();
    node_map[n->id()] = n;
  }

  // create breif node map
  for (auto &itr : brief_node_map) {
    for (Node *node : itr.second->node->inlinks) {
      itr.second->inlinks.push_back(brief_node_map[node->id()]);
    }

    for (Node *node : itr.second->node->outlinks) {
      itr.second->outlinks.push_back(brief_node_map[node->id()]);
    }
  }

  for (auto &itr : brief_node_map) {
    BriefNode *brief_node = itr.second;

    if (!brief_node->node->attr(kMarkerAttrName).Bool()) {
      VLOG(4) << brief_node->node->id() << " node not a trt candicate.";
      continue;
    }

    //  Our algorithm must guarantee that:
    //  1. The graph is always directed acyclic graph（DAG）.
    //  2. If there is a path in the subgraph from X to Y (X and Y are both
    //  nodes in the subgraph), then all paths from X to Y are in the
    //  subgraph.
    //
    //  In order to achieve the above guarantee.
    //  For adjacent nodes src -> dst.
    //  1. Get all dst input nodes except src.
    //  2. Reverse DFS from those input nodes
    //  3. If there is a path from input nodes to src,
    //  then the src and dst nodes can not be fused into one node,
    //  otherwise it can be done.

    while (true) {
      std::unordered_set<BriefNode *> contract_nodes;
      for (auto *out : brief_node->outlinks) {
        // must be an trt candidate
        if (!out->node->attr(kMarkerAttrName).Bool()) continue;
        // get all dst input nodes except src.
        std::vector<BriefNode *> source_nodes;
        for (auto *n : out->inlinks) {
          if (n != brief_node) {
            source_nodes.push_back(n);
          }
        }

        // Reverse DFS from the source_nodes.
        bool have_excess_path = false;
        FlexibleDFS(source_nodes, true, nullptr,
                    [&have_excess_path, brief_node](const BriefNode *n) {
                      if (n == brief_node) {
                        have_excess_path = true;
                        return false;
                      }
                      return true;
                    });
        if (have_excess_path) continue;
        contract_nodes.insert(out);
      }
      if (contract_nodes.empty()) break;

      for (auto dst_node : contract_nodes) {
        UnionFindCombine(node_map, brief_node->node->id(),
                         dst_node->node->id());
        UnionContractedNodes(brief_node_map, brief_node->node->id(),
                             dst_node->node->id());
      }
    }
  }

  std::unordered_map<int /*ancestor*/, std::vector<Node *>> clusters;
  for (auto *n : marked_nodes) {
    if (n->type() == Node::Type::kFunction) {
      clusters[UnionFindGetAncestor(node_map,
                                    n->attr(kUnionFindParent).Int32())]
          .push_back(n);
    }
  }
  std::vector<std::vector<Node *>> result;
  std::for_each(clusters.begin(), clusters.end(),
                [&](const decltype(clusters)::value_type &it) {
                  result.push_back(it.second);
                });

  return result;
}

void SubGraphFuse::operator()() { ReplaceNodesWithSubGraphs(); }

void SubGraphFuse::ReplaceNodesWithSubGraphs() {
  auto subgraphs = SubGraphSplitter(graph_, node_inside_subgraph_teller_)();
  for (auto &subgraph : subgraphs) {
    std::unordered_set<Node *> subgraph_uniq(subgraph.begin(), subgraph.end());
    // replace this sub-graph with the first node. Two steps: 1. Create a Block
    // Node that contains this subgraph 2. Mark the nodes inside the sub-graph
    // as deleted. 3. Replace the deleted node with the new Block Node.
    auto *block_node = static_cast<FunctionBlock *>(
        graph_->nodes.Create(Node::Type::kFunctionBlock));
    auto io = ExtractInputAndOutputOfSubGraph(subgraph);
    block_node->inlinks = std::move(io.first);
    block_node->outlinks = std::move(io.second);

    for (auto *node : subgraph) {
      // TODO(Superjomn) need a unified mechanism to treat deleted node in each
      // pass.
      node->SetDeleted();
      block_node->subgraph.push_back(node);
    }

    // Change all the sub-graph's inputs and outputs corresponding inlink and
    // outlink to this sub-graph node.
    auto inlink_or_outlink_cleaner = [&](std::vector<Node *> &nodes) {
      for (auto *&n : nodes) {
        if (subgraph_uniq.count(n)) {
          n = block_node;
        }
      }
      std::unordered_set<Node *> uniq(nodes.begin(), nodes.end());
      nodes.assign(uniq.begin(), uniq.end());
    };
    for (auto *i : block_node->inlinks) {
      inlink_or_outlink_cleaner(i->outlinks);
    }
    for (auto *&o : block_node->outlinks) {
      inlink_or_outlink_cleaner(o->inlinks);
    }
  }
  FilterRedundantOutputOfSubGraph(graph_);
}

}  // namespace analysis
}  // namespace inference
}  // namespace paddle
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Axel Naumann <axel@cern.ch>
//------------------------------------------------------------------------------

#include "cling/MetaProcessor/MetaProcessor.h"

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

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

#include "llvm/Support/Path.h"

#include <fstream>
#include <cstdlib>
#include <cctype>

using namespace clang;

namespace cling {

  MetaProcessor::MetaProcessor(Interpreter& interp) : m_Interp(interp) {
    m_InputValidator.reset(new InputValidator());
    m_MetaParser.reset(new MetaParser(new MetaSema(interp, *this)));
  }

  MetaProcessor::~MetaProcessor() {}

  int MetaProcessor::process(const char* input_text,
                             StoredValueRef* result /*=0*/,
                             Interpreter::CompilationResult* compRes /*=0*/ ) {
    int expectedIndent = m_InputValidator->getExpectedIndent();
    if (compRes) {
      if (expectedIndent) {
        *compRes = Interpreter::kMoreInputExpected;
      } else {
        *compRes = Interpreter::kSuccess;
      }
    }
    if (!input_text || !input_text[0]) {
      // nullptr / empty string, nothing to do.
      return expectedIndent;
    }
    std::string input_line(input_text);
    if (input_line == "\n") { // just a blank line, nothing to do.
      return expectedIndent;
    }
    //  Check for and handle meta commands.
    m_MetaParser->enterNewInputLine(input_line);
    if (m_MetaParser->isMetaCommand()) {

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

      //TODO: set the compilation result if there was error in the meta commands
      return expectedIndent;
    }

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

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

    return 0;
  }

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

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

  // Run a file: .x file[(args)]
  bool MetaProcessor::executeFile(llvm::StringRef file, llvm::StringRef args,
                                  StoredValueRef* result,
                               Interpreter::CompilationResult* compRes /*=0*/) {
    // Look for start of parameters:
    typedef std::pair<llvm::StringRef,llvm::StringRef> StringRefPair;

    StringRefPair pairPathFile = file.rsplit('/');
    if (pairPathFile.second.empty()) {
       pairPathFile.second = pairPathFile.first;
    }
    StringRefPair pairFuncExt = pairPathFile.second.rsplit('.');

    Interpreter::CompilationResult interpRes = m_Interp.loadFile(file);
    if (interpRes == Interpreter::kSuccess) {
      std::string expression = pairFuncExt.first.str() + "(" + args.str() + ")";
      m_CurrentlyExecutingFile = file;
      bool topmost = !m_TopExecutingFile.data();
      if (topmost)
        m_TopExecutingFile = m_CurrentlyExecutingFile;
      if (result)
        interpRes = m_Interp.evaluate(expression, *result);
      else
        interpRes = m_Interp.execute(expression);
      m_CurrentlyExecutingFile = llvm::StringRef();
      if (topmost)
        m_TopExecutingFile = llvm::StringRef();
    }
    if (compRes) *compRes = interpRes;
    return (interpRes != Interpreter::kFailure);
  }

  Interpreter::CompilationResult
  MetaProcessor::readInputFromFile(llvm::StringRef filename,
                                 StoredValueRef* result /* = 0 */,
                                 bool ignoreOutmostBlock /*=false*/) {

    {
      // check that it's not binary:
      std::ifstream in(filename.str().c_str(), std::ios::in | std::ios::binary);
      char magic[1024] = {0};
      in.read(magic, sizeof(magic));
      size_t readMagic = in.gcount();
      if (readMagic >= 4) {
        llvm::sys::LLVMFileType fileType
          = llvm::sys::IdentifyFileType(magic, 4);
        if (fileType != llvm::sys::Unknown_FileType) {
          llvm::errs() << "Error in cling::MetaProcessor: "
            "cannot read input from a binary file!\n";
          return Interpreter::kFailure;
        }
        unsigned printable = 0;
        for (size_t i = 0; i < readMagic; ++i)
          if (isprint(magic[i]))
            ++printable;
        if (10 * printable <  5 * readMagic) {
          // 50% printable for ASCII files should be a safe guess.
          llvm::errs() << "Error in cling::MetaProcessor: "
            "cannot read input from a (likely) binary file!\n" << printable;
          return Interpreter::kFailure;
        }
      }
    }

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

    if (ignoreOutmostBlock && !content.empty()) {
      static const char whitespace[] = " \t\r\n";
      std::string::size_type posNonWS = content.find_first_not_of(whitespace);
      if (posNonWS != std::string::npos) {
        if (content[posNonWS] == '{') {
          // hide the curly brace:
          content[posNonWS] = ' ';
          // and the matching closing '}'
          posNonWS = content.find_last_not_of(whitespace);
          if (posNonWS != std::string::npos) {
            if (content[posNonWS] == ';' && content[posNonWS-1] == '}') {
              content[posNonWS--] = ' '; // replace ';' and enter next if
            }
            if (content[posNonWS] == '}') {
              content[posNonWS] = ' '; // replace '}'
            } else {
              llvm::errs() << "Error in cling::MetaProcessor: missing closing '}'!\n";
              // be confident, just go on.
            }
          } // find '}'
        } // have '{'
      } // have non-whitespace
    } // ignore outmost block

    std::string strFilename(filename.str());
    m_CurrentlyExecutingFile = strFilename;
    bool topmost = !m_TopExecutingFile.data();
    if (topmost)
      m_TopExecutingFile = m_CurrentlyExecutingFile;
    Interpreter::CompilationResult ret = Interpreter::kSuccess;
    process(content.c_str(), result, &ret);
    m_CurrentlyExecutingFile = llvm::StringRef();
    if (topmost)
      m_TopExecutingFile = llvm::StringRef();
    return ret;
  }

} // end namespace cling
<commit_msg>Use the stored value in MP; Invoke process instead of it's shortcuts. Should fix savannah #98725<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Axel Naumann <axel@cern.ch>
//------------------------------------------------------------------------------

#include "cling/MetaProcessor/MetaProcessor.h"

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

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

#include "llvm/Support/Path.h"

#include <fstream>
#include <cstdlib>
#include <cctype>

using namespace clang;

namespace cling {

  MetaProcessor::MetaProcessor(Interpreter& interp) : m_Interp(interp) {
    m_InputValidator.reset(new InputValidator());
    m_MetaParser.reset(new MetaParser(new MetaSema(interp, *this)));
  }

  MetaProcessor::~MetaProcessor() {}

  int MetaProcessor::process(const char* input_text,
                             StoredValueRef* result /*=0*/,
                             Interpreter::CompilationResult* compRes /*=0*/ ) {
    int expectedIndent = m_InputValidator->getExpectedIndent();
    if (compRes) {
      if (expectedIndent) {
        *compRes = Interpreter::kMoreInputExpected;
      } else {
        *compRes = Interpreter::kSuccess;
      }
    }
    if (!input_text || !input_text[0]) {
      // nullptr / empty string, nothing to do.
      return expectedIndent;
    }
    std::string input_line(input_text);
    if (input_line == "\n") { // just a blank line, nothing to do.
      return expectedIndent;
    }
    //  Check for and handle meta commands.
    m_MetaParser->enterNewInputLine(input_line);
    if (m_MetaParser->isMetaCommand()) {

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

      //TODO: set the compilation result if there was error in the meta commands
      if (result)
        *result = m_MetaParser->getLastResultedValue();
      return expectedIndent;
    }

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

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

    return 0;
  }

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

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

  // Run a file: .x file[(args)]
  bool MetaProcessor::executeFile(llvm::StringRef file, llvm::StringRef args,
                                  StoredValueRef* result,
                               Interpreter::CompilationResult* compRes /*=0*/) {
    // Look for start of parameters:
    typedef std::pair<llvm::StringRef,llvm::StringRef> StringRefPair;

    StringRefPair pairPathFile = file.rsplit('/');
    if (pairPathFile.second.empty()) {
       pairPathFile.second = pairPathFile.first;
    }
    StringRefPair pairFuncExt = pairPathFile.second.rsplit('.');

    Interpreter::CompilationResult interpRes = m_Interp.loadFile(file);
    if (interpRes == Interpreter::kSuccess) {
      std::string expression = pairFuncExt.first.str() + "(" + args.str() + ")";
      m_CurrentlyExecutingFile = file;
      bool topmost = !m_TopExecutingFile.data();
      if (topmost)
        m_TopExecutingFile = m_CurrentlyExecutingFile;

      interpRes = m_Interp.process(expression, result);

      m_CurrentlyExecutingFile = llvm::StringRef();
      if (topmost)
        m_TopExecutingFile = llvm::StringRef();
    }
    if (compRes) *compRes = interpRes;
    return (interpRes != Interpreter::kFailure);
  }

  Interpreter::CompilationResult
  MetaProcessor::readInputFromFile(llvm::StringRef filename,
                                 StoredValueRef* result /* = 0 */,
                                 bool ignoreOutmostBlock /*=false*/) {

    {
      // check that it's not binary:
      std::ifstream in(filename.str().c_str(), std::ios::in | std::ios::binary);
      char magic[1024] = {0};
      in.read(magic, sizeof(magic));
      size_t readMagic = in.gcount();
      if (readMagic >= 4) {
        llvm::sys::LLVMFileType fileType
          = llvm::sys::IdentifyFileType(magic, 4);
        if (fileType != llvm::sys::Unknown_FileType) {
          llvm::errs() << "Error in cling::MetaProcessor: "
            "cannot read input from a binary file!\n";
          return Interpreter::kFailure;
        }
        unsigned printable = 0;
        for (size_t i = 0; i < readMagic; ++i)
          if (isprint(magic[i]))
            ++printable;
        if (10 * printable <  5 * readMagic) {
          // 50% printable for ASCII files should be a safe guess.
          llvm::errs() << "Error in cling::MetaProcessor: "
            "cannot read input from a (likely) binary file!\n" << printable;
          return Interpreter::kFailure;
        }
      }
    }

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

    if (ignoreOutmostBlock && !content.empty()) {
      static const char whitespace[] = " \t\r\n";
      std::string::size_type posNonWS = content.find_first_not_of(whitespace);
      if (posNonWS != std::string::npos) {
        if (content[posNonWS] == '{') {
          // hide the curly brace:
          content[posNonWS] = ' ';
          // and the matching closing '}'
          posNonWS = content.find_last_not_of(whitespace);
          if (posNonWS != std::string::npos) {
            if (content[posNonWS] == ';' && content[posNonWS-1] == '}') {
              content[posNonWS--] = ' '; // replace ';' and enter next if
            }
            if (content[posNonWS] == '}') {
              content[posNonWS] = ' '; // replace '}'
            } else {
              llvm::errs() << "Error in cling::MetaProcessor: missing closing '}'!\n";
              // be confident, just go on.
            }
          } // find '}'
        } // have '{'
      } // have non-whitespace
    } // ignore outmost block

    std::string strFilename(filename.str());
    m_CurrentlyExecutingFile = strFilename;
    bool topmost = !m_TopExecutingFile.data();
    if (topmost)
      m_TopExecutingFile = m_CurrentlyExecutingFile;
    Interpreter::CompilationResult ret = Interpreter::kSuccess;
    process(content.c_str(), result, &ret);
    m_CurrentlyExecutingFile = llvm::StringRef();
    if (topmost)
      m_TopExecutingFile = llvm::StringRef();
    return ret;
  }

} // end namespace cling
<|endoftext|>


<commit_before>// Copyright (c) 2013-2014 Anton Kozhevnikov, Thomas Schulthess
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that
// the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
//    following disclaimer.
// 2. 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 potential.cpp
 *
 *  \brief Contains implementation oof constructor and destructor of sirius::Potential class.
 */

#include "potential.h"

namespace sirius {

Potential::Potential(Simulation_context& ctx__)
    : ctx_(ctx__),
      unit_cell_(ctx__.unit_cell()),
      comm_(ctx__.comm()),
      pseudo_density_order(9),
      mixer_(nullptr)
{
    PROFILE("sirius::Potential::Potential");

    lmax_ = std::max(ctx_.lmax_rho(), ctx_.lmax_pot());
    sht_ = std::unique_ptr<SHT>(new SHT(lmax_));

    if (lmax_ >= 0) {
        l_by_lm_ = Utils::l_by_lm(lmax_);

        /* precompute i^l */
        zil_.resize(lmax_ + 1);
        for (int l = 0; l <= lmax_; l++) {
            zil_[l] = std::pow(double_complex(0, 1), l);
        }

        zilm_.resize(Utils::lmmax(lmax_));
        for (int l = 0, lm = 0; l <= lmax_; l++) {
            for (int m = -l; m <= l; m++, lm++) {
                zilm_[lm] = zil_[l];
            }
        }
    }

    effective_potential_ = std::unique_ptr<Periodic_function<double>>(new Periodic_function<double>(ctx_, ctx_.lmmax_pot(), 1));

    //int need_gvec = (ctx_.full_potential()) ? 0 : 1;
    int need_gvec{1};
    for (int j = 0; j < ctx_.num_mag_dims(); j++) {
        effective_magnetic_field_[j] = new Periodic_function<double>(ctx_, ctx_.lmmax_pot(), need_gvec);
    }

    hartree_potential_ = new Periodic_function<double>(ctx_, ctx_.lmmax_pot(), 1);
    hartree_potential_->allocate_mt(false);

    xc_potential_ = new Periodic_function<double>(ctx_, ctx_.lmmax_pot(), 0);
    xc_potential_->allocate_mt(false);

    xc_energy_density_ = new Periodic_function<double>(ctx_, ctx_.lmmax_pot(), 0);
    xc_energy_density_->allocate_mt(false);

    if (!ctx_.full_potential()) {
        local_potential_ = new Periodic_function<double>(ctx_, 0, 0);
        local_potential_->zero();

        generate_local_potential();
    }

    vh_el_ = mdarray<double, 1>(unit_cell_.num_atoms());

    if (ctx_.full_potential()) {
        gvec_ylm_ = mdarray<double_complex, 2>(ctx_.lmmax_pot(), ctx_.gvec().gvec_count(comm_.rank()));
        for (int igloc = 0; igloc < ctx_.gvec().gvec_count(comm_.rank()); igloc++) {
            int ig = ctx_.gvec().gvec_offset(comm_.rank()) + igloc;
            auto rtp = SHT::spherical_coordinates(ctx_.gvec().gvec_cart(ig));
            SHT::spherical_harmonics(ctx_.lmax_pot(), rtp[1], rtp[2], &gvec_ylm_(0, igloc));
        }
    }

    init();

    /* create list of XC functionals */
    for (auto& xc_label: ctx_.xc_functionals()) {
        xc_func_.push_back(new XC_functional(xc_label, ctx_.num_spins()));
    }

    /* in case of PAW */
    init_PAW();
}

Potential::~Potential()
{
    for (int j = 0; j < ctx_.num_mag_dims(); j++) delete effective_magnetic_field_[j];
    delete hartree_potential_;
    delete xc_potential_;
    delete xc_energy_density_;
    if (!ctx_.full_potential()) delete local_potential_;
    if (mixer_ != nullptr) delete mixer_;
    for (auto& ixc: xc_func_) delete ixc;
}

}
<commit_msg>store PW coeffs separately<commit_after>// Copyright (c) 2013-2014 Anton Kozhevnikov, Thomas Schulthess
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that
// the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
//    following disclaimer.
// 2. 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 potential.cpp
 *
 *  \brief Contains implementation oof constructor and destructor of sirius::Potential class.
 */

#include "potential.h"

namespace sirius {

Potential::Potential(Simulation_context& ctx__)
    : ctx_(ctx__),
      unit_cell_(ctx__.unit_cell()),
      comm_(ctx__.comm()),
      pseudo_density_order(9),
      mixer_(nullptr)
{
    PROFILE("sirius::Potential::Potential");

    lmax_ = std::max(ctx_.lmax_rho(), ctx_.lmax_pot());
    sht_ = std::unique_ptr<SHT>(new SHT(lmax_));

    if (lmax_ >= 0) {
        l_by_lm_ = Utils::l_by_lm(lmax_);

        /* precompute i^l */
        zil_.resize(lmax_ + 1);
        for (int l = 0; l <= lmax_; l++) {
            zil_[l] = std::pow(double_complex(0, 1), l);
        }

        zilm_.resize(Utils::lmmax(lmax_));
        for (int l = 0, lm = 0; l <= lmax_; l++) {
            for (int m = -l; m <= l; m++, lm++) {
                zilm_[lm] = zil_[l];
            }
        }
    }

    effective_potential_ = std::unique_ptr<Periodic_function<double>>(new Periodic_function<double>(ctx_, ctx_.lmmax_pot(), 1));

    //int need_gvec = (ctx_.full_potential()) ? 0 : 1;
    int need_gvec{1};
    for (int j = 0; j < ctx_.num_mag_dims(); j++) {
        effective_magnetic_field_[j] = new Periodic_function<double>(ctx_, ctx_.lmmax_pot(), need_gvec);
    }

    hartree_potential_ = new Periodic_function<double>(ctx_, ctx_.lmmax_pot(), 1);
    hartree_potential_->allocate_mt(false);

    xc_potential_ = new Periodic_function<double>(ctx_, ctx_.lmmax_pot(), 0);
    xc_potential_->allocate_mt(false);

    xc_energy_density_ = new Periodic_function<double>(ctx_, ctx_.lmmax_pot(), 0);
    xc_energy_density_->allocate_mt(false);

    if (!ctx_.full_potential()) {
        local_potential_ = new Periodic_function<double>(ctx_, 0, 0);
        local_potential_->zero();

        generate_local_potential();
    }

    vh_el_ = mdarray<double, 1>(unit_cell_.num_atoms());

    if (ctx_.full_potential()) {
        gvec_ylm_ = mdarray<double_complex, 2>(ctx_.lmmax_pot(), ctx_.gvec().gvec_count(comm_.rank()));
        for (int igloc = 0; igloc < ctx_.gvec().gvec_count(comm_.rank()); igloc++) {
            int ig = ctx_.gvec().gvec_offset(comm_.rank()) + igloc;
            auto rtp = SHT::spherical_coordinates(ctx_.gvec().gvec_cart(ig));
            SHT::spherical_harmonics(ctx_.lmax_pot(), rtp[1], rtp[2], &gvec_ylm_(0, igloc));
        }
    }

    if (ctx_.full_potential()) {
        switch (ctx_.valence_relativity()) {
            case relativity_t::iora: {
                rm2_inv_pw_ = mdarray<double_complex, 1>(ctx_.gvec().num_gvec());
            }
            case relativity_t::zora: {
                rm_inv_pw_ = mdarray<double_complex, 1>(ctx_.gvec().num_gvec());
            }
            default: {
                veff_pw_ = mdarray<double_complex, 1>(ctx_.gvec().num_gvec());
            }
        }
    }

    init();

    /* create list of XC functionals */
    for (auto& xc_label: ctx_.xc_functionals()) {
        xc_func_.push_back(new XC_functional(xc_label, ctx_.num_spins()));
    }

    /* in case of PAW */
    init_PAW();
}

Potential::~Potential()
{
    for (int j = 0; j < ctx_.num_mag_dims(); j++) delete effective_magnetic_field_[j];
    delete hartree_potential_;
    delete xc_potential_;
    delete xc_energy_density_;
    if (!ctx_.full_potential()) delete local_potential_;
    if (mixer_ != nullptr) delete mixer_;
    for (auto& ixc: xc_func_) delete ixc;
}

}
<|endoftext|>


<commit_before>#include "moab/Core.hpp"
#include "moab/MeshTopoUtil.hpp"
#ifdef MOAB_HAVE_MPI
#include "moab/ParallelComm.hpp"
#include "MBParallelConventions.h"
#endif
#include <Epetra_MpiComm.h>
#include <Epetra_CrsMatrix.h>
#include <Epetra_Map.h>
#include <Epetra_Vector.h>
#include <Epetra_Version.h>
#include <AztecOO.h>
#include <mpi.h>
#include <iostream>
#include <string>
#include <set>
#include <numeric>
#include <cstdlib>
#include <cstdio>
#include <cmath>

#define ALL_PROCS -1
#define ALL_DIM -1
#define GHOST_DIM 3
#define BRIDGE_DIM 2

using namespace std;
using namespace moab;

class TPFASolver {
    Interface *mbcore;
    ParallelComm *pcomm;
    MeshTopoUtil *topo_util;
    char *perm_tag_name;
    char *centroid_tag_name;
    char *dirichlet_tag_name;
    char *neumann_tag_name;
public:
    TPFASolver ();
    TPFASolver (Interface*, char*, char*, char*, char*);
    virtual ~TPFASolver ();
    void run_method ();
private:
    double calculate_equivalent_perm (double k1[9], double k2[9], double u[3]);
    double calculate_centroid_dist (double c1[3], double c2[3]);
    double* calculate_unit_vector (double c1[3], double c2[3]);
};

TPFASolver::TPFASolver () {
    this->mbcore = new Core ();
    this->pcomm = new ParallelComm (this->mbcore, MPI_COMM_SELF);
    this->topo_util = new MeshTopoUtil (mbcore);
    this->perm_tag_name = "PERMEABILITY";
    this->centroid_tag_name = "CENTROID";
    this->dirichlet_tag_name = "DIRICHLET_BC";
    this->neumann_tag_name = "NEUMANN_BC";
}

TPFASolver::TPFASolver (Interface *mbcore, char* perm_tag_name, char *centroid_tag_name,
                        char* dirichlet_tag_name, char* neumann_tag_name) {
    this->mbcore = mbcore;
    this->pcomm = new ParallelComm (this->mbcore, MPI_COMM_WORLD);
    this->topo_util = new MeshTopoUtil (this->mbcore);
    this->perm_tag_name = perm_tag_name;
    this->centroid_tag_name = centroid_tag_name;
    this->dirichlet_tag_name = dirichlet_tag_name;
    this->neumann_tag_name = neumann_tag_name;
}

TPFASolver::~TPFASolver () {
    delete this->mbcore;
    delete this->pcomm;
    delete this->topo_util;
    free(this->perm_tag_name);
    free(this->dirichlet_tag_name);
    free(this->neumann_tag_name);
}

void TPFASolver::run_method () {
    return;
}

double TPFASolver::calculate_equivalent_perm (double k1[9], double k2[9], double u[3]) {
    double k1_pre[3] = {k1[0]*u[0], k1[4]*u[1], k1[8]*u[2]};
    double k2_pre[3] = {k2[0]*u[0], k2[4]*u[1], k2[8]*u[2]};
    double k1_post = k1_pre[0]*u[0] + k1_pre[1]*u[1] + k1_pre[2]*u[2];
    double k2_post = k2_pre[0]*u[0] + k2_pre[1]*u[1] + k2_pre[2]*u[2];
    return 2*k1_post*k2_post/(k1_post + k2_post);
}

double TPFASolver::calculate_centroid_dist (double c1[3], double c2[3]) {
    return std::sqrt(std::pow(c1[0] + c2[0], 2) + std::pow(c1[1] + c2[1], 2) + std::pow(c1[2] + c2[2], 2));
}

double* TPFASolver::calculate_unit_vector (double c1[3], double c2[3]) {
    double dist = this->calculate_centroid_dist(c1, c2);
    double u[3] = {(c2[0] - c1[0])/dist, (c2[1] - c1[1])/dist, (c2[2] - c1[2])/dist};
    return u;
}

int main(int argc, char const *argv[])
{

    return 0;
}
<commit_msg>Add files via upload<commit_after>/* C++ STL includes */
#include <iostream>	/* std::cout, std::cin */
#include <numeric>	/* std::accumulate */
#include <cstdlib>	/* calloc, free */
#include <cstdio>	/* printf */
#include <cmath>	/* sqrt, pow */

/* MOAB includes */
#include "moab/Core.hpp"
#include "moab/MeshTopoUtil.hpp"
#ifdef MOAB_HAVE_MPI
#include "moab/ParallelComm.hpp"
#include "MBParallelConventions.h"
#endif

/* Trilinos includes */
#include <Epetra_MpiComm.h>
#include <Epetra_CrsMatrix.h>
#include <Epetra_Map.h>
#include <Epetra_Vector.h>
#include <Epetra_Version.h>
#include <AztecOO.h>

/* MPI header */
#include <mpi.h>

#define ALL_PROCS -1
#define ALL_DIM -1
#define GHOST_DIM 3
#define BRIDGE_DIM 2

using namespace std;
using namespace moab;

// Enumeration created to make the access to tags more readable.
enum TagsID {global_id, permeability, centroid, dirichlet, neumann};

class TPFASolver {
    Interface *mb;
    ParallelComm *pcomm;
    MeshTopoUtil *topo_util;
    MPIComm comm;
    char *perm_tag_name;
    char *centroid_tag_name;
    char *dirichlet_tag_name;
    char *neumann_tag_name;

public:
    TPFASolver () {
    	/* Default constructor */
    	this->mb = new Core ();
		this->comm = MPI_COMM_WORLD;
		this->pcomm = new ParallelComm (this->mb, this->comm);
		this->topo_util = new MeshTopoUtil (mb);
		this->perm_tag_name = "PERMEABILITY";
		this->centroid_tag_name = "CENTROID";
		this->dirichlet_tag_name = "DIRICHLET_BC";
		this->neumann_tag_name = "NEUMANN_BC";
    }

	TPFASolver (Interface *mb, MPIComm comm, char* perm_tag_name, char *centroid_tag_name,
	            char* dirichlet_tag_name, char* neumann_tag_name) {
	    /* Main constructor */
		this->mb = mb;
		this->comm = comm;
		this->pcomm = new ParallelComm (this->mb, this->comm);
		this->topo_util = new MeshTopoUtil (this->mb);
		this->perm_tag_name = perm_tag_name;
		this->centroid_tag_name = centroid_tag_name;
		this->dirichlet_tag_name = dirichlet_tag_name;
		this->neumann_tag_name = neumann_tag_name;
	}

    virtual ~TPFASolver () {
    	/* Destructor */
    	delete this->mb;
		delete this->pcomm;
		delete this->topo_util;
		free(this->perm_tag_name);
		free(this->dirichlet_tag_name);
		free(this->neumann_tag_name);
    }

    void run () {
    	/*
    		Run solver for TPFA problem specificed at given moab::Core
    		instance.

    		Parameters
    		----------
    		None

    		Returns
    		-------
    		None
    	*/

    	ErrorCode rval;
    	int rank = this->pcomm->proc_config().proc_rank();

    	// Get all volumes in the mesh and exchange those shared with
    	// others processors.
    	Range volumes;
    	rval = this->mb->get_entities_by_dimension(0, 3, volumes, false);
    	MB_CHK_SET_ERR(rval, "get_entitites_by_dimension failed");
    	rval = this->pcomm->exchange_ghost_cells(GHOST_DIM, BRIDGE_DIM, 1, 0, true);
    	MB_CHK_SET_ERR(rval, "exchange_ghost_cells failed");

    	// Calculate the total numbers of elements in the mesh.
    	int num_local_elems = volumes.size(), num_global_elems = 0;
    	MPIAllreduce(&num_local_elems, &num_global_elems, 1, MPI_INT, MPI_SUM, this->comm);

    	// Get tags on elements and exchange those from shared elements.
    	Tag* tag_handles = this->setup_tags();
    	int* gids = (int*) calloc(volumes.size(), sizeof(int));
    	if (gids == NULL) {
    		printf("<%d> Error: Null pointer\n", rank);
    		exit(EXIT_FAILURE);
    	}
    	rval = this->mb->tag_get_data(tag_handles[global_id], volumes, (void*) gids);
    	MB_CHK_SET_ERR(rval, "tag_get_data for gids failed");

    	// Setting up Epetra structures
    	Epetra_MpiComm epetra_comm (this->comm);
    	Epetra_Map row_map (num_global_elems, num_local_elems, gids, 0, epetra_comm);
    	Epetra_CrsMatrix A (Copy, row_map, 6);
	    Epetra_Vector b (row_map);
		Epetra_Vector X (row_map);

		this->assembly_matrix(&A, &b, volumes, tags_handles);

		Epetra_LinearProblem linear_problem (&A, &X, &b);
	    AztecOO solver (linear_problem);
		solver.Iterate(10000, 1e-14);

		this->set_pressure_tags(X, volumes);

		free(gids);
    }

private:
    double calculate_centroid_dist (double c1[3], double c2[3]) {
    	/*
    		Calculate the distance between two points.

    		Parameters
    		----------
    		c1: double*
    			An array with the coordinates of the first point.
    		c2: double*
    			An array with the coordinates of the second point.

    		Returns
    		-------
    		Double value of the distance between c1 and c2.
    	*/

    	return sqrt(pow(c1[0] - c2[0], 2) + pow(c1[1] - c2[1], 2) + pow(c1[2] - c2[2], 2));
    }

    double calculate_equivalent_perm (double k1[9], double k2[9], double u[3]) {
	    /*
	    	Calculate the equivalent permeability between k1 and k2. To obtain the
	    	equivalent permeability for each element, the permeability tensor is
	    	multiplied (using the inner product) by the unit vector u twice, i.e,
	    	K1_eq = <<K1, u>, u>, where <,> denotes the inner product.

	    	Parameters
	    	----------
	    	k1: double*
	    		An array representing the permeability tensor of the first element.
	    	k2: double*
		    	An array representing the permeability tensor of the second element.
		    u: double*
		    	An array representing the coordinates of the unit vector.

		    Returns
		    -------
		    Double value of the equivalent permeability of the two elements.
	    */

		double k1_pre[3] = {k1[0]*u[0] + k1[3]*u[0] + k1[6]*u[0],
		                    k1[1]*u[1] + k1[4]*u[1] + k1[7]*u[1],
		                    k1[2]*u[2] + k1[5]*u[2] + k1[8]*u[2]};
		double k2_pre[3] = {k2[0]*u[0] + k2[3]*u[0] + k2[6]*u[0],
		                    k2[1]*u[1] + k2[4]*u[1] + k2[7]*u[1],
		                    k2[2]*u[2] + k2[5]*u[2] + k2[8]*u[2]};
		double k1_eq = k1_pre[0]*u[0] + k1_pre[1]*u[1] + k1_pre[2]*u[2];
		double k2_eq = k2_pre[0]*u[0] + k2_pre[1]*u[1] + k2_pre[2]*u[2];
		return 2*k1_eq*k2_eq/(k1_eq + k2_eq);
    }

    double* calculate_unit_vector (double c1[3], double c2[3]) {
    	/*
    		Calculate the unit vector given two points.

    		Parameters
    		----------
    		c1: double*
    			An array with the coordinates of the first point.
    		c2: double*
    			An array with the coordinates of the second point.

    		Returns
    		-------
    		Array with the vector coordinates.
    	*/

    	double d = this->calculate_centroid_dist(c1, c2);
    	static double u[3] = {(c2[0] - c1[0])/d, (c2[1] - c1[1])/d, (c2[2] - c1[2])/d};
    	return u;
    }

    Tag* setup_tags () {
    	/*
    		Construct handles for tags and exchange tags for shared entities.

    		Parameters
    		----------
    		None

    		Returns
    		-------
    		Array containing handles for tags.
    	*/

    	Tag tags[5];
    	ErrorCode rval;

    	rval = this->mb->tag_get_handle("GLOBAL_ID", tags[global_id]); MB_CHK_ERR(rval);
    	rval = this->mb->tag_get_handle(this->centroid_tag_name, tags[centroid]); MB_CHK_ERR(rval);
    	rval = this->mb->tag_get_handle(this->perm_tag_name, tags[permeability]); MB_CHK_ERR(rval);
	    rval = this->mb->tag_get_handle(this->dirichlet_tag_name, tags[dirichlet]); MB_CHK_ERR(rval);
		rval = this->mb->tag_get_handle(this->neumann_tag_name, tags[neumann]); MB_CHK_ERR(rval);

		std::vector<Tag> tags_vector;
		Range empty_set;
		for (int i = 0; i < 5; i++) {
			tags_vector.push_back(tags[i]);
		}
		rval = this->pcomm->exchange_tags(tags_vector, tags_vector, empty_set);
		MB_CHK_SET_ERR(rval, "exchange_tags failed");

		return tags;
    }

    void assembly_matrix (Epetra_CrsMatrix* A, Epetra_Vector* b, Range volumes, Tag* tag_handles) {
    	/*
    		Assembly the transmissibility matrix, a.k.a, the coeficient matrix A of the linear
    		system to be solved.

    		Parameters
    		----------
    		A: Epetra_CrsMatrix*
    			Pointer to an Epetra matrix which stores the coeficients.
    		b: Epetra_Vector*
    			Pointer to an Epetra vector which stores the boundary values.
    		volumes: moab::Range
    			MOAB Range containing the entity handles for all volumes.
    		tag_handles: Tag*
    			Array of tag handles

    		Returns
    		-------
    		None
    	*/

    	Range adjacencies;
    	std::vector<double> row_values;
    	std::vector<int> row_indexes;
    	double c1[3], c2[3], k1[9], k2[9], u[3];
    	double equiv_perm = 0.0, centroid_dist = 0.0, pressure_bc = 0, flux_bc = 0, diag_coef = 0;
    	int row_id = -1, n = 0;

    	for (Range::iterator it = volumes.begin(); it != volumes.end(); it++) {
    		rval = this->mb->tag_get_data(tag_handles[dirichlet], &(*it), 1, &pressure_bc); MB_CHK_ERR(rval);
    		rval = this->mb->tag_get_data(tag_handles[neumann], &(*it), 1, &flux_bc); MB_CHK_ERR(rval);
    		if (pressure != 0) {
				diag_coef = 1;
    		}
    		else {
    			rval = this->topo_util->get_bridge_adjacencies(*it, BRIDGE_DIM, 3, adjacencies); MB_CHK_ERR(rval);
    			rval = this->mb->tag_get_data(tag_handles[centroid], &(*it), 1, &c1); MB_CHK_ERR(rval);
    			rval = this->mb->tag_get_data(tag_handles[permeability], &(*it), 1, &k1); MB_CHK_ERR(rval);
    			for (Range::iterator itt = adjacencies.begin(); itt != adjacencies.end(); itt++) {
					rval = this->mb->tag_get_data(tag_handles[centroid], &(*itt), 1, &c2); MB_CHK_ERR(rval);
    				rval = this->mb->tag_get_data(tag_handles[permeability], &(*itt), 1, &k2); MB_CHK_ERR(rval);
    				rval = this->mb->tag_get_data(tag_handles[global_id], &(*itt), 1, &row_id); MB_CHK_ERR(rval);
    				centroid_dist = this->calculate_centroid_dist(c1, c2);
    				u = this->calculate_unit_vector(c1, c2);
    				equiv_perm = this->calculate_equiv_perm(k1, k2, u);
    				row_values.push_back(-equiv_perm/pow(centroid_dist, 2));
    				row_indexes.push_back(row_id);
    			}
    			diag_coef = -accumulate(row_values.begin(), row_values.end(), 0.0);
    		}
    		rval = this->mb->tag_get_data(tag_handles[global_id], &(*it), 1, &row_id); MB_CHK_ERR(rval);
    		row_values.push_back(diag_coef);
    		row_indexes.push_back(row_id);
    		A->InsertGlobalValues(row_id, row_values.size(), &row_values[0], &row_indexes[0]);
    		if (flux_bc != -1)
    			B[n++] = pressure_bc + flux_bc;
    		else
    			B[n++] = pressure_bc;
    		row_values.clear();
    		row_indexes.clear();
    		adjacencies.clear();
    	}
    	A->FillComplete();
    }

    void set_pressure_tags (Epetra_Vector X, Range volumes) {
    	/*
    		Create and set values for the pressure on each volume.

    		Parameters
    		----------
    		X: Epetra_Vector
    			Epetra vector containing the pressure values for each volume.
    		volumes: moab::Range
    			MOAB Range containing the entity handles for all volumes.
    	*/

    	Tag pressure_tag;
    	rval = this->mb->tag_get_handle("PRESSURE", 1, MB_TYPE_DOUBLE, pressure_tag, MB_TAG_DENSE | MB_TAG_CREAT);
    	MB_CHK_SET_ERR(rval, "tag_get_handle for pressure tag failed");
    	rval = this->mb->tag_set_data(pressure_tag, volumes, &X[0]);
    	MB_CHK_SET_ERR(rval, "tag_set_data for pressure tag failed");
    }
};

int main(int argc, char const *argv[]) {

    return 0;
}
<|endoftext|>


<commit_before>// @(#)root/gl:$Id$
// Author:  Olivier Couet  17/04/2007

/*************************************************************************
 * Copyright (C) 1995-2006, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/
#include "Riostream.h"
#include "TROOT.h"

#include "TGLIncludes.h"
#include "TGLUtil.h"
#include "TGLAxis.h"
#include "TGLText.h"
#include "TColor.h"
#include "TString.h"
#include "TMath.h"
#include "THLimitsFinder.h"

//______________________________________________________________________________
/* Begin_Html

GL Axis

To draw a 3D axis in a GL window. The labels are drawn using FTGL.
End_Html */

ClassImp(TGLAxis)

//______________________________________________________________________________
TGLAxis::TGLAxis(): TAttLine(1,1,1), TAttText(20,0.,1,42,0.04)
{
   // Constructor.

   Init();
}

//______________________________________________________________________________
void TGLAxis::Init()
{
   // Default initialization.

   fNDiv = fNDiv1 = fNDiv2 = fNDiv3 = 0;
   fNTicks1 = fNTicks2 = 0;
   fTicks1          = 0;
   fTicks2          = 0;
   fLabels          = 0;
   fText            = 0;
   fAngle1          = 90.;
   fAngle2          = 0.;
   fAngle3          = 0.;
   fAxisLength      = 0.;
   fWmin = fWmax    = 0.;
   fTickMarksLength = 0.04; // % of fAxisLength
   fTickMarksOrientation = 2; // can be 0, 1, 2, or 3
   fLabelsOffset    = 0.09; // % of fAxisLength
   fLabelsSize      = 0.06; // % of fAxisLength
   fGridLength      = 0.;   // 0 means no grid
   fNDiv            = 0;
   fNDiv1           = 0;
   fNDiv2           = 0;
   fNDiv3           = 0;
   fNTicks1         = 0;
   fNTicks2         = 0;
   fWmax            = 0.;
   fWmin            = 0.;
}

//______________________________________________________________________________
TGLAxis::~TGLAxis()
{
   // Destructor.

   if (fTicks1) delete [] fTicks1;
   if (fTicks2) delete [] fTicks2;
   if (fLabels) delete [] fLabels;
   if (fText)   delete fText;
}

//______________________________________________________________________________
void TGLAxis::PaintGLAxis(const Double_t p1[3], const Double_t p2[3],
                          Double_t wmin,  Double_t wmax, Int_t ndiv,
                          Option_t *opt)
{
   // Paint GL Axis.
   //
   // p1, p2     : Axis position in the 3D space.
   // wmin, wmax : Minimum and maximum values along the axis. wmin < wmax.
   // ndiv       : Number of axis divisions. It is an integer in the form
   //              "ttsspp" where "tt" is the number of tertiary divisions,
   //              "ss" is the number of secondary divisions and "pp" the
   //              number of primary divisions.
   // opt        : Options.
   //              "N" - By default the number of divisions is optimized to
   //                    get a nice labeling. When option "N" is given, the
   //                    number of divisions is not optimized.

   fNDiv = ndiv;
   if (wmax<=wmin) {
      fWmax = wmin;
      fWmin = wmax;
   } else {
      fWmax = wmax;
      fWmin = wmin;
   }

   // Compute the axis length.
   Double_t x1 = p1[0], y1 = p1[1], z1 = p1[2];
   Double_t x2 = p2[0], y2 = p2[1], z2 = p2[2];
   fAxisLength = TMath::Sqrt((x2-x1)*(x2-x1)+
                             (y2-y1)*(y2-y1)+
                             (z2-z1)*(z2-z1));

   TicksPositions(opt);

   DoLabels();

   // Paint using GL
   glPushMatrix();

   // Translation
   glTranslatef(x1, y1, z1);

   // Rotation in the Z plane
   Double_t phi=0;
   Double_t normal[3];
   normal[0] = 0;
   normal[1] = 1;
   normal[2] = 0;
   if (z1!=z2) {
      if (y2==y1 && x2==x1) {
         if (z2<z1) phi = 90;
         else       phi = 270;
      } else {
         Double_t p3[3];
         p3[0] = p2[0]; p3[1] = p2[1]; p3[2] = 0;
         TMath::Normal2Plane(p1, p2, p3, normal);
         phi = TMath::ACos(TMath::Abs(z2-z1)/fAxisLength);
         phi = -(90-(180/TMath::Pi())*phi);
      }
      glRotatef(phi, normal[0], normal[1], normal[2]);
   }

   // Rotation in the XY plane
   Double_t theta = 0;
   if (y2!=y1) {
      if ((x2-x1)>0) {
         theta = TMath::ATan((y2-y1)/(x2-x1));
         theta = (180/TMath::Pi())*theta;
      } else if ((x2-x1)<0) {
         theta = TMath::ATan((y2-y1)/(x2-x1));
         theta = 180+(180/TMath::Pi())*theta;
      } else {
         if (y2>y1) theta = 90;
         else       theta = 270;
      }
   } else {
      if (x2<x1) theta = 180;
   }
   glRotatef(theta, 0., 0., 1.);

   PaintGLAxisBody();

   PaintGLAxisTickMarks();

   PaintGLAxisLabels();

   glPopMatrix();
}

//______________________________________________________________________________
void TGLAxis::PaintGLAxisBody()
{
   // Paint horizontal axis body at position (0,0,0)

   TColor *col;
   Float_t red, green, blue;
   col = gROOT->GetColor(GetLineColor());
   col->GetRGB(red, green, blue);
   glColor3d(red, green, blue);
   TGLUtil::LineWidth(GetLineWidth());
   glBegin(GL_LINES);
   glVertex3d(0., 0., 0.);
   glVertex3d(fAxisLength, 0., 0.);
   glEnd();
}

//______________________________________________________________________________
void TGLAxis::PaintGLAxisTickMarks()
{
   // Paint axis tick marks.

   Int_t i;

   // Ticks marks orientation;
   Double_t yo=0, zo=0;
   switch (fTickMarksOrientation) {
      case 0:
         yo = 0;
         zo = 1;
      break;
      case 1:
         yo = -1;
         zo = 0;
      break;
      case 2:
         yo = 0;
         zo = -1;
      break;
      case 3:
         yo = 1;
         zo = 0;
      break;
   }

   // Paint level 1 tick marks.
   if (fTicks1) {
      // Paint the tick marks, if needed.
      if (fTickMarksLength) {
         Double_t tl = fTickMarksLength*fAxisLength;
         glBegin(GL_LINES);
         for (i=0; i<fNTicks1 ; i++) {
            glVertex3f( fTicks1[i], 0, 0);
            glVertex3f( fTicks1[i], yo*tl, zo*tl);
         }
         glEnd();
      }

      // Paint the grid, if needed, on level 1 tick marks.
      if (fGridLength) {
         const UShort_t stipple = 0x8888;
         glLineStipple(1, stipple);
         glEnable(GL_LINE_STIPPLE);
         glBegin(GL_LINES);
         for (i=0; i<fNTicks1; i++) {
            glVertex3f( fTicks1[i], 0, 0);
            glVertex3f( fTicks1[i], -yo*fGridLength, -zo*fGridLength);
         }
         glEnd();
         glDisable(GL_LINE_STIPPLE);
      }
   }

   // Paint level 2 tick marks.
   if (fTicks2) {
      if (fTickMarksLength) {
         Double_t tl = 0.5*fTickMarksLength*fAxisLength;
         glBegin(GL_LINES);
         for (i=0; i<fNTicks2; i++) {
            glVertex3f( fTicks2[i], 0, 0);
            glVertex3f( fTicks2[i], yo*tl, zo*tl);
         }
         glEnd();
      }
   }
}

//______________________________________________________________________________
void TGLAxis::PaintGLAxisLabels()
{
   // Paint axis labels on the main tick marks.

   if (!fLabelsSize) return;

   Double_t x=0,y=0,z=0;
   Int_t i;

   if (!fText) {
      fText = new TGLText();
      fText->SetTextColor(GetTextColor());
      fText->SetGLTextFont(GetTextFont());
      fText->SetTextSize(fLabelsSize*fAxisLength);
      fText->SetTextAlign(GetTextAlign());
   }
   fText->SetGLTextAngles(fAngle1, fAngle2, fAngle3);

   switch (fTickMarksOrientation) {
      case 0:
         y = 0;
         z = fLabelsOffset*fAxisLength;
      break;
      case 1:
         y = -fLabelsOffset*fAxisLength;
         z = 0;
      break;
      case 2:
         y = 0;
         z = -fLabelsOffset*fAxisLength;
      break;
      case 3:
         y = fLabelsOffset*fAxisLength;
         z = 0;
      break;
   }
   for (i=0; i<fNDiv1+1 ; i++) {
      x = fTicks1[i];
      fText->PaintGLText(x,y,z,fLabels[i]);
   }
}

//______________________________________________________________________________
void TGLAxis::TicksPositions(Option_t *opt)
{
   // Compute ticks positions.

   Bool_t optionNoopt, optionLog;

   if (strchr(opt,'N')) optionNoopt = kTRUE;  else optionNoopt = kFALSE;
   if (strchr(opt,'G')) optionLog   = kTRUE;  else optionLog   = kFALSE;

   // Determine number of tick marks 1, 2 and 3.
   fNDiv3 = fNDiv/10000;
   fNDiv2 = (fNDiv-10000*fNDiv3)/100;
   fNDiv1 = fNDiv%100;

   // Clean the tick marks arrays if they exist.
   if (fTicks1) {
      delete [] fTicks1;
      fTicks1 = 0;
   }
   if (fTicks2) {
      delete [] fTicks2;
      fTicks2 = 0;
   }

   // Compute the tick marks positions according to the options.
   if (optionNoopt) {
      TicksPositionsNoOpt();
   } else {
      TicksPositionsOpt();
   }
}

//______________________________________________________________________________
void TGLAxis::TicksPositionsNoOpt()
{
   // Compute ticks positions. Linear and not optimized.

   Int_t i, j, k;
   Double_t step1 = fAxisLength/(fNDiv1);

   fNTicks1 = fNDiv1+1;
   fTicks1  = new Double_t[fNTicks1];

   // Level 1 tick marks.
   for (i=0; i<fNTicks1; i++) fTicks1[i] = i*step1;

   // Level 2 tick marks.
   if (fNDiv2) {
      Double_t t2;
      Double_t step2 = step1/fNDiv2;
      fNTicks2       = fNDiv1*(fNDiv2-1);
      fTicks2        = new Double_t[fNTicks2];
      k = 0;
      for (i=0; i<fNTicks1-1; i++) {
         t2 = fTicks1[i]+step2;
         for (j=0; j<fNDiv2-1; j++) {
            fTicks2[k] = t2;
            k++;
            t2 = t2+step2;
         }
      }
   }
}

//______________________________________________________________________________
void TGLAxis::TicksPositionsOpt()
{
   // Compute ticks positions. Linear and optimized.

   Int_t i, j, k, nDivOpt;
   Double_t step1, step2, wmin2, wmax2;
   Double_t wmin = fWmin;
   Double_t wmax = fWmax;

   // Level 1 tick marks.
   THLimitsFinder::Optimize(wmin,  wmax, fNDiv1,
                            fWmin, fWmax, nDivOpt,
                            step1, "");
   fNDiv1   = nDivOpt;
   fNTicks1 = fNDiv1+1;
   fTicks1  = new Double_t[fNTicks1];

   Double_t r = fAxisLength/(wmax-wmin);
   Double_t w = fWmin;
   i = 0;
   while (w<=fWmax) {
      fTicks1[i] = r*(w-wmin);
      i++;
      w = w+step1;
   }

   // Level 2 tick marks.
   if (fNDiv2) {
      Double_t t2;
      THLimitsFinder::Optimize(fWmin, fWmin+step1, fNDiv2,
                               wmin2, wmax2, nDivOpt,
                               step2, "");
      fNDiv2       = nDivOpt;
      step2        = TMath::Abs((fTicks1[1]-fTicks1[0])/fNDiv2);
      Int_t nTickl = (Int_t)(fTicks1[0]/step2);
      Int_t nTickr = (Int_t)((fAxisLength-fTicks1[fNTicks1-1])/step2);
      fNTicks2     = fNDiv1*(fNDiv2-1)+nTickl+nTickr;
      fTicks2      = new Double_t[fNTicks2];
      k = 0;
      for (i=0; i<fNTicks1-1; i++) {
         t2 = fTicks1[i]+step2;
         for (j=0; j<fNDiv2-1; j++) {
            fTicks2[k] = t2;
            k++;
            t2 = t2+step2;
         }
      }
      if (nTickl) {
         t2 = fTicks1[0]-step2;
         for (i=0; i<nTickl; i++) {
            fTicks2[k] = t2;
            k++;
            t2 = t2-step2;
         }
      }
      if (nTickr) {
         t2 = fTicks1[fNTicks1-1]+step2;
         for (i=0; i<nTickr; i++) {
            fTicks2[k] = t2;
            k++;
            t2 = t2+step2;
         }
      }
   }
}

//______________________________________________________________________________
void TGLAxis::DoLabels()
{
   // Do labels.

   if (fLabels) delete [] fLabels;
   fLabels = new TString[fNTicks1];
   Int_t i;

   // Make regular labels between fWmin and fWmax.
   Double_t dw = (fWmax-fWmin)/(fNDiv1);
   for (i=0; i<fNTicks1; i++) {
      fLabels[i] = Form("%g",fWmin+i*dw);
   }
}

//______________________________________________________________________________
void TGLAxis::SetLabelsAngles(Double_t a1, Double_t a2, Double_t a3)
{
   // Set labels' angles.

   fAngle1 = a1;
   fAngle2 = a2;
   fAngle3 = a3;
}
<commit_msg>Undo double correction of coverity warnings :)<commit_after>// @(#)root/gl:$Id$
// Author:  Olivier Couet  17/04/2007

/*************************************************************************
 * Copyright (C) 1995-2006, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/
#include "Riostream.h"
#include "TROOT.h"

#include "TGLIncludes.h"
#include "TGLUtil.h"
#include "TGLAxis.h"
#include "TGLText.h"
#include "TColor.h"
#include "TString.h"
#include "TMath.h"
#include "THLimitsFinder.h"

//______________________________________________________________________________
/* Begin_Html

GL Axis

To draw a 3D axis in a GL window. The labels are drawn using FTGL.
End_Html */

ClassImp(TGLAxis)

//______________________________________________________________________________
TGLAxis::TGLAxis(): TAttLine(1,1,1), TAttText(20,0.,1,42,0.04)
{
   // Constructor.

   Init();
}

//______________________________________________________________________________
void TGLAxis::Init()
{
   // Default initialization.

   fNDiv = fNDiv1 = fNDiv2 = fNDiv3 = 0;
   fNTicks1 = fNTicks2 = 0;
   fTicks1          = 0;
   fTicks2          = 0;
   fLabels          = 0;
   fText            = 0;
   fAngle1          = 90.;
   fAngle2          = 0.;
   fAngle3          = 0.;
   fAxisLength      = 0.;
   fWmin = fWmax    = 0.;
   fTickMarksLength = 0.04; // % of fAxisLength
   fTickMarksOrientation = 2; // can be 0, 1, 2, or 3
   fLabelsOffset    = 0.09; // % of fAxisLength
   fLabelsSize      = 0.06; // % of fAxisLength
   fGridLength      = 0.;   // 0 means no grid
}

//______________________________________________________________________________
TGLAxis::~TGLAxis()
{
   // Destructor.

   if (fTicks1) delete [] fTicks1;
   if (fTicks2) delete [] fTicks2;
   if (fLabels) delete [] fLabels;
   if (fText)   delete fText;
}

//______________________________________________________________________________
void TGLAxis::PaintGLAxis(const Double_t p1[3], const Double_t p2[3],
                          Double_t wmin,  Double_t wmax, Int_t ndiv,
                          Option_t *opt)
{
   // Paint GL Axis.
   //
   // p1, p2     : Axis position in the 3D space.
   // wmin, wmax : Minimum and maximum values along the axis. wmin < wmax.
   // ndiv       : Number of axis divisions. It is an integer in the form
   //              "ttsspp" where "tt" is the number of tertiary divisions,
   //              "ss" is the number of secondary divisions and "pp" the
   //              number of primary divisions.
   // opt        : Options.
   //              "N" - By default the number of divisions is optimized to
   //                    get a nice labeling. When option "N" is given, the
   //                    number of divisions is not optimized.

   fNDiv = ndiv;
   if (wmax<=wmin) {
      fWmax = wmin;
      fWmin = wmax;
   } else {
      fWmax = wmax;
      fWmin = wmin;
   }

   // Compute the axis length.
   Double_t x1 = p1[0], y1 = p1[1], z1 = p1[2];
   Double_t x2 = p2[0], y2 = p2[1], z2 = p2[2];
   fAxisLength = TMath::Sqrt((x2-x1)*(x2-x1)+
                             (y2-y1)*(y2-y1)+
                             (z2-z1)*(z2-z1));

   TicksPositions(opt);

   DoLabels();

   // Paint using GL
   glPushMatrix();

   // Translation
   glTranslatef(x1, y1, z1);

   // Rotation in the Z plane
   Double_t phi=0;
   Double_t normal[3];
   normal[0] = 0;
   normal[1] = 1;
   normal[2] = 0;
   if (z1!=z2) {
      if (y2==y1 && x2==x1) {
         if (z2<z1) phi = 90;
         else       phi = 270;
      } else {
         Double_t p3[3];
         p3[0] = p2[0]; p3[1] = p2[1]; p3[2] = 0;
         TMath::Normal2Plane(p1, p2, p3, normal);
         phi = TMath::ACos(TMath::Abs(z2-z1)/fAxisLength);
         phi = -(90-(180/TMath::Pi())*phi);
      }
      glRotatef(phi, normal[0], normal[1], normal[2]);
   }

   // Rotation in the XY plane
   Double_t theta = 0;
   if (y2!=y1) {
      if ((x2-x1)>0) {
         theta = TMath::ATan((y2-y1)/(x2-x1));
         theta = (180/TMath::Pi())*theta;
      } else if ((x2-x1)<0) {
         theta = TMath::ATan((y2-y1)/(x2-x1));
         theta = 180+(180/TMath::Pi())*theta;
      } else {
         if (y2>y1) theta = 90;
         else       theta = 270;
      }
   } else {
      if (x2<x1) theta = 180;
   }
   glRotatef(theta, 0., 0., 1.);

   PaintGLAxisBody();

   PaintGLAxisTickMarks();

   PaintGLAxisLabels();

   glPopMatrix();
}

//______________________________________________________________________________
void TGLAxis::PaintGLAxisBody()
{
   // Paint horizontal axis body at position (0,0,0)

   TColor *col;
   Float_t red, green, blue;
   col = gROOT->GetColor(GetLineColor());
   col->GetRGB(red, green, blue);
   glColor3d(red, green, blue);
   TGLUtil::LineWidth(GetLineWidth());
   glBegin(GL_LINES);
   glVertex3d(0., 0., 0.);
   glVertex3d(fAxisLength, 0., 0.);
   glEnd();
}

//______________________________________________________________________________
void TGLAxis::PaintGLAxisTickMarks()
{
   // Paint axis tick marks.

   Int_t i;

   // Ticks marks orientation;
   Double_t yo=0, zo=0;
   switch (fTickMarksOrientation) {
      case 0:
         yo = 0;
         zo = 1;
      break;
      case 1:
         yo = -1;
         zo = 0;
      break;
      case 2:
         yo = 0;
         zo = -1;
      break;
      case 3:
         yo = 1;
         zo = 0;
      break;
   }

   // Paint level 1 tick marks.
   if (fTicks1) {
      // Paint the tick marks, if needed.
      if (fTickMarksLength) {
         Double_t tl = fTickMarksLength*fAxisLength;
         glBegin(GL_LINES);
         for (i=0; i<fNTicks1 ; i++) {
            glVertex3f( fTicks1[i], 0, 0);
            glVertex3f( fTicks1[i], yo*tl, zo*tl);
         }
         glEnd();
      }

      // Paint the grid, if needed, on level 1 tick marks.
      if (fGridLength) {
         const UShort_t stipple = 0x8888;
         glLineStipple(1, stipple);
         glEnable(GL_LINE_STIPPLE);
         glBegin(GL_LINES);
         for (i=0; i<fNTicks1; i++) {
            glVertex3f( fTicks1[i], 0, 0);
            glVertex3f( fTicks1[i], -yo*fGridLength, -zo*fGridLength);
         }
         glEnd();
         glDisable(GL_LINE_STIPPLE);
      }
   }

   // Paint level 2 tick marks.
   if (fTicks2) {
      if (fTickMarksLength) {
         Double_t tl = 0.5*fTickMarksLength*fAxisLength;
         glBegin(GL_LINES);
         for (i=0; i<fNTicks2; i++) {
            glVertex3f( fTicks2[i], 0, 0);
            glVertex3f( fTicks2[i], yo*tl, zo*tl);
         }
         glEnd();
      }
   }
}

//______________________________________________________________________________
void TGLAxis::PaintGLAxisLabels()
{
   // Paint axis labels on the main tick marks.

   if (!fLabelsSize) return;

   Double_t x=0,y=0,z=0;
   Int_t i;

   if (!fText) {
      fText = new TGLText();
      fText->SetTextColor(GetTextColor());
      fText->SetGLTextFont(GetTextFont());
      fText->SetTextSize(fLabelsSize*fAxisLength);
      fText->SetTextAlign(GetTextAlign());
   }
   fText->SetGLTextAngles(fAngle1, fAngle2, fAngle3);

   switch (fTickMarksOrientation) {
      case 0:
         y = 0;
         z = fLabelsOffset*fAxisLength;
      break;
      case 1:
         y = -fLabelsOffset*fAxisLength;
         z = 0;
      break;
      case 2:
         y = 0;
         z = -fLabelsOffset*fAxisLength;
      break;
      case 3:
         y = fLabelsOffset*fAxisLength;
         z = 0;
      break;
   }
   for (i=0; i<fNDiv1+1 ; i++) {
      x = fTicks1[i];
      fText->PaintGLText(x,y,z,fLabels[i]);
   }
}

//______________________________________________________________________________
void TGLAxis::TicksPositions(Option_t *opt)
{
   // Compute ticks positions.

   Bool_t optionNoopt, optionLog;

   if (strchr(opt,'N')) optionNoopt = kTRUE;  else optionNoopt = kFALSE;
   if (strchr(opt,'G')) optionLog   = kTRUE;  else optionLog   = kFALSE;

   // Determine number of tick marks 1, 2 and 3.
   fNDiv3 = fNDiv/10000;
   fNDiv2 = (fNDiv-10000*fNDiv3)/100;
   fNDiv1 = fNDiv%100;

   // Clean the tick marks arrays if they exist.
   if (fTicks1) {
      delete [] fTicks1;
      fTicks1 = 0;
   }
   if (fTicks2) {
      delete [] fTicks2;
      fTicks2 = 0;
   }

   // Compute the tick marks positions according to the options.
   if (optionNoopt) {
      TicksPositionsNoOpt();
   } else {
      TicksPositionsOpt();
   }
}

//______________________________________________________________________________
void TGLAxis::TicksPositionsNoOpt()
{
   // Compute ticks positions. Linear and not optimized.

   Int_t i, j, k;
   Double_t step1 = fAxisLength/(fNDiv1);

   fNTicks1 = fNDiv1+1;
   fTicks1  = new Double_t[fNTicks1];

   // Level 1 tick marks.
   for (i=0; i<fNTicks1; i++) fTicks1[i] = i*step1;

   // Level 2 tick marks.
   if (fNDiv2) {
      Double_t t2;
      Double_t step2 = step1/fNDiv2;
      fNTicks2       = fNDiv1*(fNDiv2-1);
      fTicks2        = new Double_t[fNTicks2];
      k = 0;
      for (i=0; i<fNTicks1-1; i++) {
         t2 = fTicks1[i]+step2;
         for (j=0; j<fNDiv2-1; j++) {
            fTicks2[k] = t2;
            k++;
            t2 = t2+step2;
         }
      }
   }
}

//______________________________________________________________________________
void TGLAxis::TicksPositionsOpt()
{
   // Compute ticks positions. Linear and optimized.

   Int_t i, j, k, nDivOpt;
   Double_t step1, step2, wmin2, wmax2;
   Double_t wmin = fWmin;
   Double_t wmax = fWmax;

   // Level 1 tick marks.
   THLimitsFinder::Optimize(wmin,  wmax, fNDiv1,
                            fWmin, fWmax, nDivOpt,
                            step1, "");
   fNDiv1   = nDivOpt;
   fNTicks1 = fNDiv1+1;
   fTicks1  = new Double_t[fNTicks1];

   Double_t r = fAxisLength/(wmax-wmin);
   Double_t w = fWmin;
   i = 0;
   while (w<=fWmax) {
      fTicks1[i] = r*(w-wmin);
      i++;
      w = w+step1;
   }

   // Level 2 tick marks.
   if (fNDiv2) {
      Double_t t2;
      THLimitsFinder::Optimize(fWmin, fWmin+step1, fNDiv2,
                               wmin2, wmax2, nDivOpt,
                               step2, "");
      fNDiv2       = nDivOpt;
      step2        = TMath::Abs((fTicks1[1]-fTicks1[0])/fNDiv2);
      Int_t nTickl = (Int_t)(fTicks1[0]/step2);
      Int_t nTickr = (Int_t)((fAxisLength-fTicks1[fNTicks1-1])/step2);
      fNTicks2     = fNDiv1*(fNDiv2-1)+nTickl+nTickr;
      fTicks2      = new Double_t[fNTicks2];
      k = 0;
      for (i=0; i<fNTicks1-1; i++) {
         t2 = fTicks1[i]+step2;
         for (j=0; j<fNDiv2-1; j++) {
            fTicks2[k] = t2;
            k++;
            t2 = t2+step2;
         }
      }
      if (nTickl) {
         t2 = fTicks1[0]-step2;
         for (i=0; i<nTickl; i++) {
            fTicks2[k] = t2;
            k++;
            t2 = t2-step2;
         }
      }
      if (nTickr) {
         t2 = fTicks1[fNTicks1-1]+step2;
         for (i=0; i<nTickr; i++) {
            fTicks2[k] = t2;
            k++;
            t2 = t2+step2;
         }
      }
   }
}

//______________________________________________________________________________
void TGLAxis::DoLabels()
{
   // Do labels.

   if (fLabels) delete [] fLabels;
   fLabels = new TString[fNTicks1];
   Int_t i;

   // Make regular labels between fWmin and fWmax.
   Double_t dw = (fWmax-fWmin)/(fNDiv1);
   for (i=0; i<fNTicks1; i++) {
      fLabels[i] = Form("%g",fWmin+i*dw);
   }
}

//______________________________________________________________________________
void TGLAxis::SetLabelsAngles(Double_t a1, Double_t a2, Double_t a3)
{
   // Set labels' angles.

   fAngle1 = a1;
   fAngle2 = a2;
   fAngle3 = a3;
}
<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	RX24T グループ A/D 制御 @n
			Copyright 2016 Kunihito Hiramatsu
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include "common/renesas.hpp"
#include "common/vect.h"
#include "RX24T/port_map.hpp"
#include "RX24T/power_cfg.hpp"

/// F_PCKD は変換パラメーター計算で必要で、設定が無いとエラーにします。
#ifndef F_PCKD
#  error "adc_io.hpp requires F_PCKD to be defined"
#endif

namespace device {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  A/D 制御クラス
		@param[in]	ADCU	A/D チャネル・ユニット
		@param[in]	TASK	割り込みタスク
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class ADCU, class TASK>
	class adc_io {
	public:

		typedef ADCU value_type;

		//-----------------------------------------------------------------//
		/*!
			@brief	変換モード
		 */
		//-----------------------------------------------------------------//
		enum class cnv_type : uint8_t {

		};

	private:
		static TASK task_;

		static INTERRUPT_FUNC void adi_task_()
		{
			task_();
		}

		uint8_t	level_;

		static inline void sleep_() { asm("nop"); }

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief	コンストラクター
		 */
		//-----------------------------------------------------------------//
		adc_io() : level_(0) { }

		//-----------------------------------------------------------------//
		/*!
			@brief	スタート
			@param[in]	ana		アナログ入力
			@param[in]	level	割り込みレベル、０の場合はポーリング
			@return 成功なら「true」
		 */
		//-----------------------------------------------------------------//
		bool start(typename ADCU::analog ana, uint8_t level = 0)
		{
			level_ = level;

			// 基本変換時間（１マイクロ秒）＋マージン
			uint32_t n = F_PCKD / 1000000 + 10;
			if(n > 255) return false;

			power_cfg::turn(ADCU::get_peripheral());
			ADCU::enable(ana);
			ADCU::ADANSA.set(ana);
			ADCU::ADSSTR.set(ana, n);

			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	スキャン開始
		 */
		//-----------------------------------------------------------------//
		void scan() {
			if(level_) {
				set_interrupt_task(adi_task_, static_cast<uint32_t>(ADCU::get_vec()));
				icu_mgr::set_level(ADCU::get_peripheral(), level_);
				ADCU::ADCSR = ADCU::ADCSR.ADST.b() | ADCU::ADCSR.ADIE.b();
			} else {
				ADCU::ADCSR = ADCU::ADCSR.ADST.b();
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	変換状態の取得
			@return 変換中なら「true」
		 */
		//-----------------------------------------------------------------//
		bool get_state() const {
			return ADCU::ADCSR.ADST();
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	読み込み同期
		 */
		//-----------------------------------------------------------------//
		void sync() const {
			while(ADCU::ADCSR.ADST() != 0) sleep_();
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	A/D 変換結果を取得
			@param[in]	an	変換チャネル
			@return 変換結果（上位１０ビットが有効な値）
		 */
		//-----------------------------------------------------------------//
		uint16_t get(typename ADCU::analog an) const {
			return ADCU::ADDR(an);
		}
	};

	template <class ADCU, class TASK>
	TASK adc_io<ADCU, TASK>::task_;
}
<commit_msg>fix include path<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	RX24T グループ A/D 制御 @n
			Copyright 2016,2017 Kunihito Hiramatsu
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include "RX24T/icu_mgr.hpp"
#include "RX24T/port_map.hpp"
#include "RX24T/power_cfg.hpp"
#include "common/vect.h"

/// F_PCKD は変換パラメーター計算で必要で、設定が無いとエラーにします。
#ifndef F_PCKD
#  error "adc_io.hpp requires F_PCKD to be defined"
#endif

namespace device {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  A/D 制御クラス
		@param[in]	ADCU	A/D チャネル・ユニット
		@param[in]	TASK	割り込みタスク
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class ADCU, class TASK>
	class adc_io {
	public:

		typedef ADCU value_type;

		//-----------------------------------------------------------------//
		/*!
			@brief	変換モード
		 */
		//-----------------------------------------------------------------//
		enum class cnv_type : uint8_t {

		};

	private:
		static TASK task_;

		static INTERRUPT_FUNC void adi_task_()
		{
			task_();
		}

		uint8_t	level_;

		static inline void sleep_() { asm("nop"); }

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief	コンストラクター
		 */
		//-----------------------------------------------------------------//
		adc_io() : level_(0) { }

		//-----------------------------------------------------------------//
		/*!
			@brief	スタート
			@param[in]	ana		アナログ入力
			@param[in]	level	割り込みレベル、０の場合はポーリング
			@return 成功なら「true」
		 */
		//-----------------------------------------------------------------//
		bool start(typename ADCU::analog ana, uint8_t level = 0)
		{
			level_ = level;

			// 基本変換時間（１マイクロ秒）＋マージン
			uint32_t n = F_PCKD / 1000000 + 10;
			if(n > 255) return false;

			power_cfg::turn(ADCU::get_peripheral());
			ADCU::enable(ana);
			ADCU::ADANSA.set(ana);
			ADCU::ADSSTR.set(ana, n);

			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	スキャン開始
		 */
		//-----------------------------------------------------------------//
		void scan() {
			if(level_) {
				set_interrupt_task(adi_task_, static_cast<uint32_t>(ADCU::get_vec()));
				icu_mgr::set_level(ADCU::get_peripheral(), level_);
				ADCU::ADCSR = ADCU::ADCSR.ADST.b() | ADCU::ADCSR.ADIE.b();
			} else {
				ADCU::ADCSR = ADCU::ADCSR.ADST.b();
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	変換状態の取得
			@return 変換中なら「true」
		 */
		//-----------------------------------------------------------------//
		bool get_state() const {
			return ADCU::ADCSR.ADST();
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	読み込み同期
		 */
		//-----------------------------------------------------------------//
		void sync() const {
			while(ADCU::ADCSR.ADST() != 0) sleep_();
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	A/D 変換結果を取得
			@param[in]	an	変換チャネル
			@return 変換結果（上位１０ビットが有効な値）
		 */
		//-----------------------------------------------------------------//
		uint16_t get(typename ADCU::analog an) const {
			return ADCU::ADDR(an);
		}
	};

	template <class ADCU, class TASK>
	TASK adc_io<ADCU, TASK>::task_;
}
<|endoftext|>