<commit_before>// Copyright (c) 2021 The Orbit Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "UserSpaceInstrumentation/Attach.h"

#include <absl/container/flat_hash_set.h>
#include <absl/strings/str_format.h>
#include <errno.h>
#include <sys/ptrace.h>
#include <sys/wait.h>

#include <chrono>
#include <string>
#include <thread>
#include <utility>
#include <vector>

#include "OrbitBase/GetProcessIds.h"
#include "OrbitBase/SafeStrerror.h"

namespace orbit_user_space_instrumentation {

using orbit_base::GetTidsOfProcess;

namespace {

// Attaches to the thread using ptrace.
// Returns true if the thread was halted and false if the thread did not exist anymore.
[[nodiscard]] ErrorMessageOr<bool> AttachAndStopThread(pid_t tid) {
  if (ptrace(PTRACE_ATTACH, tid, nullptr, nullptr) == -1) {
    // If tid has ended already we get ESRCH; if the thread was in 'exit state' we get EPERM.
    // There are a bunch of other (non-relevant) cases. I haven't found documentation on this but it
    // can be looked up in the function `ptrace_attach` in `ptrace.c` in the kernel sources.
    if (errno == ESRCH || errno == EPERM) {
      return false;
    }
    return ErrorMessage(
        absl::StrFormat("PTRACE_ATTACH failed for %d: %s", tid, SafeStrerror(errno)));
  }
  // Wait for the traced thread to stop. Timeout after one second.
  constexpr int kMaxAttempts = 1000;
  for (int i = 0; i < kMaxAttempts; i++) {
    int stat_val = 0;
    const int waitpid_result = waitpid(tid, &stat_val, WNOHANG);
    if (waitpid_result == -1) {
      return ErrorMessage(absl::StrFormat("Wait for thread to get traced failed for tid %d: %s",
                                          tid, SafeStrerror(errno)));
    }
    if (waitpid_result > 0) {
      // Occasionally the thread is active during PTRACE_ATTACH but terminates before it gets
      // descheduled. So waitpid returns on exit of the thread instead of the expected stop.
      if (WIFEXITED(stat_val)) {
        return false;
      }
      if (WIFSTOPPED(stat_val)) {
        return true;
      }
      return ErrorMessage(absl::StrFormat(
          "Wait for thread to get traced yielded unexpected result for tid %d: %d", tid, stat_val));
    }
    std::this_thread::sleep_for(std::chrono::milliseconds(1));
  }

  ptrace(PTRACE_DETACH, tid, nullptr, nullptr);
  return ErrorMessage(absl::StrFormat("Waiting for the traced thread %d to stop timed out.", tid));
}

}  // namespace

ErrorMessageOr<absl::flat_hash_set<pid_t>> AttachAndStopProcess(pid_t pid) {
  ErrorMessageOr<pid_t> error_or_tracer_pid = orbit_base::GetTracerPidOfProcess(pid);
  if (error_or_tracer_pid.has_error()) {
    return ErrorMessage(absl::StrFormat("There is no process with pid %d: %s", pid,
                                        error_or_tracer_pid.error().message()));
  }

  const pid_t tracer_pid = error_or_tracer_pid.value();
  if (tracer_pid != 0) {
    return ErrorMessage(
        absl::StrFormat("Process %d is already being traced by %d. Please make sure no debugger is "
                        "attached to the target process when profiling.",
                        pid, tracer_pid));
  }

  return AttachAndStopNewThreadsOfProcess(pid, {});
}

[[nodiscard]] ErrorMessageOr<absl::flat_hash_set<pid_t>> AttachAndStopNewThreadsOfProcess(
    pid_t pid, absl::flat_hash_set<pid_t> already_halted_tids) {
  std::vector<pid_t> process_tids = GetTidsOfProcess(pid);
  absl::flat_hash_set<pid_t> halted_tids{std::move(already_halted_tids)};
  // Note that the process is still running - it can spawn and end threads at this point.
  while (process_tids.size() != halted_tids.size()) {
    for (const auto tid : process_tids) {
      if (halted_tids.contains(tid)) {
        continue;
      }
      auto result = AttachAndStopThread(tid);
      if (result.has_error()) {
        // Try to detach and return an error.
        for (const auto t : halted_tids) {
          if (ptrace(PTRACE_DETACH, tid, nullptr, nullptr) == -1) {
            return ErrorMessage(absl::StrFormat(
                "Unable to attach to thread: %d. Also unable to clean up. We are still "
                "attached to thread: %d",
                tid, t));
          }
        }
        return ErrorMessage(absl::StrFormat("Unable to attach to thread tid: %d", tid));
      }
      if (result.value()) {
        halted_tids.insert(tid);
      }
    }
    process_tids = GetTidsOfProcess(pid);
  }
  return halted_tids;
}

ErrorMessageOr<void> DetachAndContinueProcess(pid_t pid) {
  auto tids = GetTidsOfProcess(pid);
  for (auto tid : tids) {
    if (ptrace(PTRACE_DETACH, tid, nullptr, nullptr) == -1) {
      return ErrorMessage(
          absl::StrFormat("Error while detaching from thread %d: %s", tid, SafeStrerror(errno)));
    }
  }
  return outcome::success();
}

}  // namespace orbit_user_space_instrumentation
<commit_msg>Fix error handling when detaching from a process. (#3794)<commit_after>// Copyright (c) 2021 The Orbit Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "UserSpaceInstrumentation/Attach.h"

#include <absl/container/flat_hash_set.h>
#include <absl/strings/str_format.h>
#include <errno.h>
#include <sys/ptrace.h>
#include <sys/wait.h>

#include <chrono>
#include <string>
#include <thread>
#include <utility>
#include <vector>

#include "OrbitBase/GetProcessIds.h"
#include "OrbitBase/SafeStrerror.h"

namespace orbit_user_space_instrumentation {

using orbit_base::GetTidsOfProcess;

namespace {

// Attaches to the thread using ptrace.
// Returns true if the thread was halted and false if the thread did not exist anymore.
[[nodiscard]] ErrorMessageOr<bool> AttachAndStopThread(pid_t tid) {
  if (ptrace(PTRACE_ATTACH, tid, nullptr, nullptr) == -1) {
    // If tid has ended already we get ESRCH; if the thread was in 'exit state' we get EPERM.
    // There are a bunch of other (non-relevant) cases. I haven't found documentation on this but it
    // can be looked up in the function `ptrace_attach` in `ptrace.c` in the kernel sources.
    if (errno == ESRCH || errno == EPERM) {
      return false;
    }
    return ErrorMessage(
        absl::StrFormat("PTRACE_ATTACH failed for %d: %s", tid, SafeStrerror(errno)));
  }
  // Wait for the traced thread to stop. Timeout after one second.
  constexpr int kMaxAttempts = 1000;
  for (int i = 0; i < kMaxAttempts; i++) {
    int stat_val = 0;
    const int waitpid_result = waitpid(tid, &stat_val, WNOHANG);
    if (waitpid_result == -1) {
      return ErrorMessage(absl::StrFormat("Wait for thread to get traced failed for tid %d: %s",
                                          tid, SafeStrerror(errno)));
    }
    if (waitpid_result > 0) {
      // Occasionally the thread is active during PTRACE_ATTACH but terminates before it gets
      // descheduled. So waitpid returns on exit of the thread instead of the expected stop.
      if (WIFEXITED(stat_val)) {
        return false;
      }
      if (WIFSTOPPED(stat_val)) {
        return true;
      }
      return ErrorMessage(absl::StrFormat(
          "Wait for thread to get traced yielded unexpected result for tid %d: %d", tid, stat_val));
    }
    std::this_thread::sleep_for(std::chrono::milliseconds(1));
  }

  ptrace(PTRACE_DETACH, tid, nullptr, nullptr);
  return ErrorMessage(absl::StrFormat("Waiting for the traced thread %d to stop timed out.", tid));
}

}  // namespace

ErrorMessageOr<absl::flat_hash_set<pid_t>> AttachAndStopProcess(pid_t pid) {
  ErrorMessageOr<pid_t> error_or_tracer_pid = orbit_base::GetTracerPidOfProcess(pid);
  if (error_or_tracer_pid.has_error()) {
    return ErrorMessage(absl::StrFormat("There is no process with pid %d: %s", pid,
                                        error_or_tracer_pid.error().message()));
  }

  const pid_t tracer_pid = error_or_tracer_pid.value();
  if (tracer_pid != 0) {
    return ErrorMessage(
        absl::StrFormat("Process %d is already being traced by %d. Please make sure no debugger is "
                        "attached to the target process when profiling.",
                        pid, tracer_pid));
  }

  return AttachAndStopNewThreadsOfProcess(pid, {});
}

[[nodiscard]] ErrorMessageOr<absl::flat_hash_set<pid_t>> AttachAndStopNewThreadsOfProcess(
    pid_t pid, absl::flat_hash_set<pid_t> already_halted_tids) {
  std::vector<pid_t> process_tids = GetTidsOfProcess(pid);
  absl::flat_hash_set<pid_t> halted_tids{std::move(already_halted_tids)};
  // Note that the process is still running - it can spawn and end threads at this point.
  while (process_tids.size() != halted_tids.size()) {
    for (const auto tid : process_tids) {
      if (halted_tids.contains(tid)) {
        continue;
      }
      auto result = AttachAndStopThread(tid);
      if (result.has_error()) {
        // Try to detach and return an error.
        for (const auto t : halted_tids) {
          if (ptrace(PTRACE_DETACH, tid, nullptr, nullptr) == -1) {
            return ErrorMessage(absl::StrFormat(
                "Unable to attach to thread: %d. Also unable to clean up. We are still "
                "attached to thread: %d",
                tid, t));
          }
        }
        return ErrorMessage(absl::StrFormat("Unable to attach to thread tid: %d", tid));
      }
      if (result.value()) {
        halted_tids.insert(tid);
      }
    }
    process_tids = GetTidsOfProcess(pid);
  }
  return halted_tids;
}

ErrorMessageOr<void> DetachAndContinueProcess(pid_t pid) {
  auto tids = GetTidsOfProcess(pid);
  for (auto tid : tids) {
    if (ptrace(PTRACE_DETACH, tid, nullptr, nullptr) == -1) {
      // Failing with "no such process" is fine here: The thread might have been created (in running
      // state) after we attached to the other threads of this process and therefore we never
      // attached to this thread.
      constexpr int kErrnoNoSuchProcess = 3;
      if (errno != kErrnoNoSuchProcess) {
        return ErrorMessage(
            absl::StrFormat("Error while detaching from thread %d: %s", tid, SafeStrerror(errno)));
      }
    }
  }
  return outcome::success();
}

}  // namespace orbit_user_space_instrumentation
<|endoftext|>


<commit_before>/*
**
** Author(s):
**  - Pierre ROULLON <proullon@aldebaran-robotics.com>
**
** Copyright (C) 2012, 2013 Aldebaran Robotics
*/

#include <qi/log.hpp>
#include <qi/future.hpp>

#include <qitype/anyobject.hpp>
#include <qitype/dynamicobjectbuilder.hpp>
#include <qitype/anyfunction.hpp>

#include <callbridge.hpp>
#include <jobjectconverter.hpp>
#include <jnitools.hpp>

qiLogCategory("qimessaging.jni");

MethodInfoHandler gInfoHandler;

qi::Future<qi::AnyReference>* call_from_java(JNIEnv *env, qi::AnyObject object, const std::string& strMethodName, jobjectArray listParams)
{
  qi::GenericFunctionParameters params;
  jsize size;
  jsize i = 0;

  size = env->GetArrayLength(listParams);
  while (i < size)
  {
    jobject current = env->NewGlobalRef(env->GetObjectArrayElement(listParams, i));
    qi::AnyReference val = qi::AnyReference(current).clone();
    params.push_back(val);

    i++;
  }

  qi::Future<qi::AnyReference> *fut = new qi::Future<qi::AnyReference>();
  try
  {
    *fut = object->metaCall(strMethodName, params);
  } catch (std::runtime_error &e)
  {
    throwJavaError(env, e.what());
    return 0;
  }

  // Destroy arguments
  i = 0;
  for(qi::GenericFunctionParameters::iterator it = params.begin(); it != params.end(); ++it)
    (*it).destroy();

  return fut;
}

qi::AnyReference call_to_java(std::string signature, void* data, const qi::GenericFunctionParameters& params)
{
  qi::AnyReference res;
  jvalue*             args = new jvalue[params.size()];
  int                 index = 0;
  JNIEnv*             env = 0;
  qi_method_info*     info = reinterpret_cast<qi_method_info*>(data);
  jclass              cls = 0;
  std::vector<std::string>  sigInfo = qi::signatureSplit(signature);

  // Attach JNIEnv to current thread to avoid segfault in jni functions. (eventloop dependent)
  if (JVM()->AttachCurrentThread((envPtr) &env, (void *) 0) != JNI_OK || env == 0)
  {
    qiLogError() << "Cannot attach callback thread to Java VM";
    throwJavaError(env, "Cannot attach callback thread to Java VM");
    return res;
  }

  // Check value of method info structure
  if (info == 0)
  {
    qiLogError() << "Internal method informations are not valid";
    throwJavaError(env, "Internal method informations are not valid");
    return res;
  }
  // Translate parameters from AnyValues to jobjects
  qi::GenericFunctionParameters::const_iterator it = params.begin();
  qi::GenericFunctionParameters::const_iterator end = params.end();
  for(; it != end; it++)
  {
    jvalue value;
    value.l = JObject_from_AnyValue(*it);
    args[index] = value;
    index++;
  }

  // Find method class and get methodID
  cls = qi::jni::clazz(info->instance);
  if (!cls)
  {
    qiLogError() << "Service class not found";
    throw std::runtime_error("Service class not found");
  }

  // Find method ID
  jmethodID mid = env->GetMethodID(cls, sigInfo[1].c_str(), toJavaSignature(signature).c_str());
  if (!mid)
    mid = env->GetStaticMethodID(cls, sigInfo[1].c_str(), toJavaSignature(signature).c_str());
  if (!mid)
  {
    qiLogError() << "Cannot find java method " << sigInfo[1] << toJavaSignature(signature).c_str();
    throw std::runtime_error("Cannot find method");
  }

  // Call method
  jobject ret = env->CallObjectMethodA(info->instance, mid, args);

  // Did method thrown ?
  if (env->ExceptionCheck())
  {
    env->ExceptionDescribe();
    env->ExceptionClear();
    throw std::runtime_error("Remote method thrown exception");
  }

  // Release instance clazz
  qi::jni::releaseClazz(cls);

  // Release arguments
  while (--index >= 0)
    qi::jni::releaseObject(args[index].l);
  delete[] args;

  // If method return signature is void, return here
  if (sigInfo[0] == "")
    return qi::AnyReference(qi::typeOf<void>());

  // Convert return value in AnyValue
  res = AnyValue_from_JObject(ret).first;
  qi::jni::releaseObject(ret);
  return res;
}

qi::AnyReference event_callback_to_java(void *vinfo, const std::vector<qi::AnyReference>& params)
{
  qi_method_info*  info = static_cast<qi_method_info*>(vinfo);

  qiLogVerbose("qimessaging.jni") << "Java event callback called (sig=" << info->sig << ")";

  return call_to_java(info->sig, info, params);
}
<commit_msg>Track random segfault on android<commit_after>/*
**
** Author(s):
**  - Pierre ROULLON <proullon@aldebaran-robotics.com>
**
** Copyright (C) 2012, 2013 Aldebaran Robotics
*/

#include <qi/log.hpp>
#include <qi/future.hpp>

#include <qitype/anyobject.hpp>
#include <qitype/dynamicobjectbuilder.hpp>
#include <qitype/anyfunction.hpp>

#include <callbridge.hpp>
#include <jobjectconverter.hpp>
#include <jnitools.hpp>

qiLogCategory("qimessaging.jni");

MethodInfoHandler gInfoHandler;

qi::Future<qi::AnyReference>* call_from_java(JNIEnv *env, qi::AnyObject object, const std::string& strMethodName, jobjectArray listParams)
{
  qi::GenericFunctionParameters params;
  jsize size;
  jsize i = 0;

  size = env->GetArrayLength(listParams);
  while (i < size)
  {
    jobject current = env->NewGlobalRef(env->GetObjectArrayElement(listParams, i));
    qi::AnyReference val = qi::AnyReference(current).clone();
    params.push_back(val);

    i++;
  }

  qi::Future<qi::AnyReference> *fut = new qi::Future<qi::AnyReference>();
  try
  {
    *fut = object->metaCall(strMethodName, params);
  } catch (std::runtime_error &e)
  {
    throwJavaError(env, e.what());
    return 0;
  }

  // Destroy arguments
//  i = 0;
//  for(qi::GenericFunctionParameters::iterator it = params.begin(); it != params.end(); ++it)
//    (*it).destroy();

  return fut;
}

qi::AnyReference call_to_java(std::string signature, void* data, const qi::GenericFunctionParameters& params)
{
  qi::AnyReference res;
  jvalue*             args = new jvalue[params.size()];
  int                 index = 0;
  JNIEnv*             env = 0;
  qi_method_info*     info = reinterpret_cast<qi_method_info*>(data);
  jclass              cls = 0;
  std::vector<std::string>  sigInfo = qi::signatureSplit(signature);

  // Attach JNIEnv to current thread to avoid segfault in jni functions. (eventloop dependent)
  if (JVM()->AttachCurrentThread((envPtr) &env, (void *) 0) != JNI_OK || env == 0)
  {
    qiLogError() << "Cannot attach callback thread to Java VM";
    throwJavaError(env, "Cannot attach callback thread to Java VM");
    return res;
  }

  // Check value of method info structure
  if (info == 0)
  {
    qiLogError() << "Internal method informations are not valid";
    throwJavaError(env, "Internal method informations are not valid");
    return res;
  }
  // Translate parameters from AnyValues to jobjects
  qi::GenericFunctionParameters::const_iterator it = params.begin();
  qi::GenericFunctionParameters::const_iterator end = params.end();
  for(; it != end; it++)
  {
    jvalue value;
    value.l = JObject_from_AnyValue(*it);
    args[index] = value;
    index++;
  }

  // Find method class and get methodID
  cls = qi::jni::clazz(info->instance);
  if (!cls)
  {
    qiLogError() << "Service class not found";
    throw std::runtime_error("Service class not found");
  }

  // Find method ID
  jmethodID mid = env->GetMethodID(cls, sigInfo[1].c_str(), toJavaSignature(signature).c_str());
  if (!mid)
    mid = env->GetStaticMethodID(cls, sigInfo[1].c_str(), toJavaSignature(signature).c_str());
  if (!mid)
  {
    qiLogError() << "Cannot find java method " << sigInfo[1] << toJavaSignature(signature).c_str();
    throw std::runtime_error("Cannot find method");
  }

  // Call method
  jobject ret = env->CallObjectMethodA(info->instance, mid, args);

  // Did method thrown ?
  if (env->ExceptionCheck())
  {
    env->ExceptionDescribe();
    env->ExceptionClear();
    throw std::runtime_error("Remote method thrown exception");
  }

  // Release instance clazz
  qi::jni::releaseClazz(cls);

  // Release arguments
  while (--index >= 0)
    qi::jni::releaseObject(args[index].l);
  delete[] args;

  // If method return signature is void, return here
  if (sigInfo[0] == "")
    return qi::AnyReference(qi::typeOf<void>());

  // Convert return value in AnyValue
  res = AnyValue_from_JObject(ret).first;
  qi::jni::releaseObject(ret);
  return res;
}

qi::AnyReference event_callback_to_java(void *vinfo, const std::vector<qi::AnyReference>& params)
{
  qi_method_info*  info = static_cast<qi_method_info*>(vinfo);

  qiLogVerbose("qimessaging.jni") << "Java event callback called (sig=" << info->sig << ")";

  return call_to_java(info->sig, info, params);
}
<|endoftext|>


<commit_before>#ifndef MJOLNIR_STRUCTURE_TOPOLOGY_H
#define MJOLNIR_STRUCTURE_TOPOLOGY_H
#include <mjolnir/util/throw_exception.hpp>
#include <algorithm>
#include <stdexcept>
#include <vector>

namespace mjolnir
{

class StructureTopology
{
  public:

    typedef std::size_t group_id_type;
    enum class connection_kind_type
    {
        bond,    //! define chains
        contact, //! does not have effect on the definition of chain
    };

    // each node corresponds to the particle having same idx in a system.
    struct node
    {
        node(): group_id(std::numeric_limits<std::size_t>::max()) {}
        ~node() = default;
        node(node const&) = default;
        node(node&&)      = default;
        node& operator=(node const&) = default;
        node& operator=(node&&)      = default;

        std::size_t group_id;
        std::vector<std::pair<std::size_t, connection_kind_type>> adjacents;
    };

  public:

    StructureTopology()  = default;
    ~StructureTopology() = default;
    StructureTopology(const StructureTopology&) = default;
    StructureTopology(StructureTopology&&)      = default;
    StructureTopology& operator=(const StructureTopology&) = default;
    StructureTopology& operator=(StructureTopology&&)      = default;

    StructureTopology(const std::size_t N): nodes_(N){};

    bool        empty() const noexcept {return nodes_.empty();}
    std::size_t size()  const noexcept {return nodes_.size();}

    void resize(const std::size_t N) {nodes_.resize(N); return;}

    void add_connection(const std::size_t i, const std::size_t j,
                        const connection_kind_type kind);

    void erase_connection(const std::size_t i, const std::size_t j);
    void erase_connection(const std::size_t i, const std::size_t j,
                          const connection_kind_type kind);

    bool has_connection(const std::size_t i, const std::size_t j);
    bool has_connection(const std::size_t i, const std::size_t j,
                        const connection_kind_type kind);

    std::vector<std::size_t>
    list_adjacent_within(const std::size_t node_idx, const std::size_t dist
                         ) const;
    std::vector<std::size_t>
    list_adjacent_within(const std::size_t node_idx, const std::size_t dist,
                         const connection_kind_type kind) const;

    std::size_t  group_of(const std::size_t idx) const
    {return nodes_.at(idx).group_id;}
    std::size_t& group_of(const std::size_t idx)
    {return nodes_.at(idx).group_id;}

  private:
    void
    list_adjacent_within(const std::size_t node_idx, const std::size_t dist,
                         std::vector<std::size_t>& out) const;
    void
    list_adjacent_within(const std::size_t node_idx, const std::size_t dist,
                         const connection_kind_type kind, std::vector<std::size_t>& out
                         ) const;
  private:
    std::vector<node> nodes_;
};

inline void StructureTopology::add_connection(
        const std::size_t i, const std::size_t j, connection_kind_type kind)
{
    if(nodes_.size() <= std::max(i, j))
    {
        throw_exception<std::out_of_range>(
            "mjolnir::StructureTopology::add_connection: size of nodes = ",
            nodes_.size(), ", i = ", i, ", j = ", j);
    }

    {
        const auto elem = std::make_pair(j, kind);
        auto& adjs = nodes_[i].adjacents;
        if(std::find(adjs.cbegin(), adjs.cend(), elem) == adjs.cend())
        {
            adjs.push_back(elem);
        }
    }
    {
        const auto elem = std::make_pair(i, kind);
        auto& adjs = nodes_[j].adjacents;
        if(std::find(adjs.cbegin(), adjs.cend(), elem) == adjs.cend())
        {
            adjs.push_back(elem);
        }
    }
    return ;
}

inline void StructureTopology::erase_connection(
        const std::size_t i, const std::size_t j)
{
    if(nodes_.size() <= std::max(i, j))
    {
        throw_exception<std::out_of_range>(
            "mjolnir::StructureTopology::erase_connection: size of nodes = ",
            nodes_.size(), ", i = ", i, ", j = ", j);
    }

    {
        auto& adjs = nodes_[i].adjacents;
        const auto found = std::find_if(adjs.begin(), adjs.end(),
            [j](const std::pair<std::size_t, connection_kind_type>& x){
                return x.first == j;
            });
        if(found != adjs.end())
        {
            adjs.erase(found);
        }
    }
    {
        auto& adjs = nodes_[j].adjacents;
        const auto found = std::find_if(adjs.begin(), adjs.end(),
            [i](const std::pair<std::size_t, connection_kind_type>& x){
                return x.first == i;
            });
        if(found != adjs.end())
        {
            adjs.erase(found);
        }
    }
    return ;
}

inline void StructureTopology::erase_connection(
        const std::size_t i, const std::size_t j,
        const connection_kind_type kind)
{
    if(nodes_.size() <= std::max(i, j))
    {
        throw_exception<std::out_of_range>(
            "mjolnir::StructureTopology::erase_connection: size of nodes = ",
            nodes_.size(), ", i = ", i, ", j = ", j);
    }

    {
        auto& adjs = nodes_[i].adjacents;
        const auto found = std::find(
                adjs.begin(), adjs.end(), std::make_pair(j, kind));
        if(found != adjs.end())
        {
            adjs.erase(found);
        }
    }
    {
        auto& adjs = nodes_[j].adjacents;
        const auto found = std::find(
                adjs.begin(), adjs.end(), std::make_pair(i, kind));
        if(found != adjs.end())
        {
            adjs.erase(found);
        }
    }
    return ;
}

inline bool StructureTopology::has_connection(
        const std::size_t i, const std::size_t j)
{
    if(nodes_.size() <= std::max(i, j))
    {
        throw_exception<std::out_of_range>(
            "mjolnir::StructureTopology::has_connection: size of nodes = ",
            nodes_.size(), ", i = ", i, ", j = ", j);
    }
    if(i == j) {return true;} // XXX

    const auto& adjs = nodes_[i].adjacents;
    const auto found = std::find_if(adjs.cbegin(), adjs.cend(),
        [j](const std::pair<std::size_t, connection_kind_type>& x){
            return x.first == j;
        });

    return found != adjs.cend();
}

inline bool StructureTopology::has_connection(
        const std::size_t i, const std::size_t j,
        const connection_kind_type kind)
{
    if(nodes_.size() <= std::max(i, j))
    {
        throw_exception<std::out_of_range>(
            "mjolnir::StructureTopology::has_connection: size of nodes = ",
            nodes_.size(), ", i = ", i, ", j = ", j);
    }
    if(i == j) {return true;} // XXX

    const auto& adjs = nodes_[i].adjacents;
    const auto found = std::find(adjs.cbegin(), adjs.cend(),
                                 std::make_pair(j, kind));
    return found != adjs.cend();
}

inline std::vector<std::size_t>
StructureTopology::list_adjacent_within(
        const std::size_t node_idx, const std::size_t dist) const
{
    std::vector<std::size_t> retval = {node_idx};
    if(dist == 0) {return retval;}

    for(auto ik : this->nodes_.at(node_idx).adjacents)
    {
        if(std::find(retval.cbegin(), retval.cend(), ik.first) != retval.cend())
        {
            continue; // already assigned. ignore it.
        }
        retval.push_back(ik.first);
        this->list_adjacent_within(ik.first, dist - 1, retval);
    }
    std::sort(retval.begin(), retval.end());
    const auto new_end = std::unique(retval.begin(), retval.end());
    retval.erase(new_end, retval.end());
    return retval;
}

inline std::vector<std::size_t>
StructureTopology::list_adjacent_within(
        const std::size_t node_idx, const std::size_t dist,
        const connection_kind_type kind) const
{
    std::vector<std::size_t> retval = {node_idx};
    if(dist == 0) {return retval;}

    for(auto ik : this->nodes_.at(node_idx).adjacents)
    {
        if(ik.second != kind ||
           std::find(retval.cbegin(), retval.cend(), ik.first) != retval.cend())
        {
            continue;
        }
        retval.push_back(ik.first);
        this->list_adjacent_within(ik.first, dist - 1, kind, retval);
    }
    std::sort(retval.begin(), retval.end());
    const auto new_end = std::unique(retval.begin(), retval.end());
    retval.erase(new_end, retval.end());
    return retval;
}

inline void StructureTopology::list_adjacent_within(
        const std::size_t node_idx, const std::size_t dist,
        std::vector<std::size_t>& out) const
{
    if(dist == 0)
    {
        if(std::find(out.cbegin(), out.cend(), node_idx) != out.cend())
        {
            out.push_back(node_idx);
        }
        return ;
    }

    for(auto ik : this->nodes_.at(node_idx).adjacents)
    {
        if(std::find(out.cbegin(), out.cend(), ik.first) != out.cend())
        {
            continue;
        }
        out.push_back(ik.first);
        this->list_adjacent_within(ik.first, dist - 1, out);
    }
    return;
}

inline void
StructureTopology::list_adjacent_within(
        const std::size_t node_idx, const std::size_t dist,
        const connection_kind_type kind, std::vector<std::size_t>& out) const
{
    if(dist == 0)
    {
        if(std::find(out.cbegin(), out.cend(), node_idx) != out.cend())
        {
            out.push_back(node_idx);
        }
        return;
    }

    for(auto ik : this->nodes_.at(node_idx).adjacents)
    {
        if(ik.second != kind ||
           std::find(out.cbegin(), out.cend(), ik.first) != out.cend())
        {
            continue;
        }
        out.push_back(ik.first);
        this->list_adjacent_within(ik.first, dist-1, kind, out);
    }
    return;
}

} // mjolnir
#endif// MJOLNIR_STRUCTURE_TOPOLOGY_H
<commit_msg>rename `group` to `chain` and add `construct_chain`<commit_after>#ifndef MJOLNIR_STRUCTURE_TOPOLOGY_H
#define MJOLNIR_STRUCTURE_TOPOLOGY_H
#include <mjolnir/util/throw_exception.hpp>
#include <algorithm>
#include <stdexcept>
#include <vector>

namespace mjolnir
{

class StructureTopology
{
  public:

    typedef std::size_t chain_id_type;
    enum class connection_kind_type
    {
        bond,    //! define chain
        contact, //! does not have effect on the chain (nonbonded contact)
    };

    static constexpr chain_id_type uninitialized() noexcept
    {
        return std::numeric_limits<chain_id_type>::max();
    }

    // each node corresponds to the particle having same idx in a system.
    struct node
    {
        node(): chain_id(uninitialized()) {}
        ~node() = default;
        node(node const&) = default;
        node(node&&)      = default;
        node& operator=(node const&) = default;
        node& operator=(node&&)      = default;

        std::size_t chain_id;
        std::vector<std::pair<std::size_t, connection_kind_type>> adjacents;
    };

  public:

    StructureTopology()  = default;
    ~StructureTopology() = default;
    StructureTopology(const StructureTopology&) = default;
    StructureTopology(StructureTopology&&)      = default;
    StructureTopology& operator=(const StructureTopology&) = default;
    StructureTopology& operator=(StructureTopology&&)      = default;

    StructureTopology(const std::size_t N): nodes_(N){};

    bool        empty() const noexcept {return nodes_.empty();}
    std::size_t size()  const noexcept {return nodes_.size();}

    void resize(const std::size_t N) {nodes_.resize(N); return;}

    void add_connection(const std::size_t i, const std::size_t j,
                        const connection_kind_type kind);

    void erase_connection(const std::size_t i, const std::size_t j);
    void erase_connection(const std::size_t i, const std::size_t j,
                          const connection_kind_type kind);

    //! reset chain_id of all the particles
    void construct_chains();

    bool has_connection(const std::size_t i, const std::size_t j);
    bool has_connection(const std::size_t i, const std::size_t j,
                        const connection_kind_type kind);

    std::vector<std::size_t>
    list_adjacent_within(const std::size_t node_idx, const std::size_t dist
                         ) const;
    std::vector<std::size_t>
    list_adjacent_within(const std::size_t node_idx, const std::size_t dist,
                         const connection_kind_type kind) const;

    chain_id_type number_of_chains() const noexcept {return this->num_chains_;}

    chain_id_type  chain_of(const std::size_t idx) const
    {return nodes_.at(idx).chain_id;}
    chain_id_type& chain_of(const std::size_t idx)
    {return nodes_.at(idx).chain_id;}

  private:
    void
    list_adjacent_within(const std::size_t node_idx, const std::size_t dist,
                         std::vector<std::size_t>& out) const;
    void
    list_adjacent_within(const std::size_t node_idx, const std::size_t dist,
                         const connection_kind_type kind, std::vector<std::size_t>& out
                         ) const;
  private:
    std::size_t  num_chains_;
    std::vector<node> nodes_;
};

inline void StructureTopology::add_connection(
        const std::size_t i, const std::size_t j, connection_kind_type kind)
{
    if(nodes_.size() <= std::max(i, j))
    {
        throw_exception<std::out_of_range>(
            "mjolnir::StructureTopology::add_connection: size of nodes = ",
            nodes_.size(), ", i = ", i, ", j = ", j);
    }

    {
        const auto elem = std::make_pair(j, kind);
        auto& adjs = nodes_[i].adjacents;
        if(std::find(adjs.cbegin(), adjs.cend(), elem) == adjs.cend())
        {
            adjs.push_back(elem);
        }
    }
    {
        const auto elem = std::make_pair(i, kind);
        auto& adjs = nodes_[j].adjacents;
        if(std::find(adjs.cbegin(), adjs.cend(), elem) == adjs.cend())
        {
            adjs.push_back(elem);
        }
    }
    return ;
}

inline void StructureTopology::erase_connection(
        const std::size_t i, const std::size_t j)
{
    if(nodes_.size() <= std::max(i, j))
    {
        throw_exception<std::out_of_range>(
            "mjolnir::StructureTopology::erase_connection: size of nodes = ",
            nodes_.size(), ", i = ", i, ", j = ", j);
    }

    {
        auto& adjs = nodes_[i].adjacents;
        const auto found = std::find_if(adjs.begin(), adjs.end(),
            [j](const std::pair<std::size_t, connection_kind_type>& x){
                return x.first == j;
            });
        if(found != adjs.end())
        {
            adjs.erase(found);
        }
    }
    {
        auto& adjs = nodes_[j].adjacents;
        const auto found = std::find_if(adjs.begin(), adjs.end(),
            [i](const std::pair<std::size_t, connection_kind_type>& x){
                return x.first == i;
            });
        if(found != adjs.end())
        {
            adjs.erase(found);
        }
    }
    return ;
}

inline void StructureTopology::erase_connection(
        const std::size_t i, const std::size_t j,
        const connection_kind_type kind)
{
    if(nodes_.size() <= std::max(i, j))
    {
        throw_exception<std::out_of_range>(
            "mjolnir::StructureTopology::erase_connection: size of nodes = ",
            nodes_.size(), ", i = ", i, ", j = ", j);
    }

    {
        auto& adjs = nodes_[i].adjacents;
        const auto found = std::find(
                adjs.begin(), adjs.end(), std::make_pair(j, kind));
        if(found != adjs.end())
        {
            adjs.erase(found);
        }
    }
    {
        auto& adjs = nodes_[j].adjacents;
        const auto found = std::find(
                adjs.begin(), adjs.end(), std::make_pair(i, kind));
        if(found != adjs.end())
        {
            adjs.erase(found);
        }
    }
    return ;
}

inline bool StructureTopology::has_connection(
        const std::size_t i, const std::size_t j)
{
    if(nodes_.size() <= std::max(i, j))
    {
        throw_exception<std::out_of_range>(
            "mjolnir::StructureTopology::has_connection: size of nodes = ",
            nodes_.size(), ", i = ", i, ", j = ", j);
    }
    if(i == j) {return true;} // XXX

    const auto& adjs = nodes_[i].adjacents;
    const auto found = std::find_if(adjs.cbegin(), adjs.cend(),
        [j](const std::pair<std::size_t, connection_kind_type>& x){
            return x.first == j;
        });

    return found != adjs.cend();
}

inline bool StructureTopology::has_connection(
        const std::size_t i, const std::size_t j,
        const connection_kind_type kind)
{
    if(nodes_.size() <= std::max(i, j))
    {
        throw_exception<std::out_of_range>(
            "mjolnir::StructureTopology::has_connection: size of nodes = ",
            nodes_.size(), ", i = ", i, ", j = ", j);
    }
    if(i == j) {return true;} // XXX

    const auto& adjs = nodes_[i].adjacents;
    const auto found = std::find(adjs.cbegin(), adjs.cend(),
                                 std::make_pair(j, kind));
    return found != adjs.cend();
}

inline std::vector<std::size_t>
StructureTopology::list_adjacent_within(
        const std::size_t node_idx, const std::size_t dist) const
{
    std::vector<std::size_t> retval = {node_idx};
    if(dist == 0) {return retval;}

    for(auto ik : this->nodes_.at(node_idx).adjacents)
    {
        if(std::find(retval.cbegin(), retval.cend(), ik.first) != retval.cend())
        {
            continue; // already assigned. ignore it.
        }
        retval.push_back(ik.first);
        this->list_adjacent_within(ik.first, dist - 1, retval);
    }
    std::sort(retval.begin(), retval.end());
    const auto new_end = std::unique(retval.begin(), retval.end());
    retval.erase(new_end, retval.end());
    return retval;
}

inline std::vector<std::size_t>
StructureTopology::list_adjacent_within(
        const std::size_t node_idx, const std::size_t dist,
        const connection_kind_type kind) const
{
    std::vector<std::size_t> retval = {node_idx};
    if(dist == 0) {return retval;}

    for(auto ik : this->nodes_.at(node_idx).adjacents)
    {
        if(ik.second != kind ||
           std::find(retval.cbegin(), retval.cend(), ik.first) != retval.cend())
        {
            continue;
        }
        retval.push_back(ik.first);
        this->list_adjacent_within(ik.first, dist - 1, kind, retval);
    }
    std::sort(retval.begin(), retval.end());
    const auto new_end = std::unique(retval.begin(), retval.end());
    retval.erase(new_end, retval.end());
    return retval;
}

inline void StructureTopology::list_adjacent_within(
        const std::size_t node_idx, const std::size_t dist,
        std::vector<std::size_t>& out) const
{
    if(dist == 0)
    {
        if(std::find(out.cbegin(), out.cend(), node_idx) != out.cend())
        {
            out.push_back(node_idx);
        }
        return ;
    }

    for(auto ik : this->nodes_.at(node_idx).adjacents)
    {
        if(std::find(out.cbegin(), out.cend(), ik.first) != out.cend())
        {
            continue;
        }
        out.push_back(ik.first);
        this->list_adjacent_within(ik.first, dist - 1, out);
    }
    return;
}

inline void
StructureTopology::list_adjacent_within(
        const std::size_t node_idx, const std::size_t dist,
        const connection_kind_type kind, std::vector<std::size_t>& out) const
{
    if(dist == 0)
    {
        if(std::find(out.cbegin(), out.cend(), node_idx) != out.cend())
        {
            out.push_back(node_idx);
        }
        return;
    }

    for(auto ik : this->nodes_.at(node_idx).adjacents)
    {
        if(ik.second != kind ||
           std::find(out.cbegin(), out.cend(), ik.first) != out.cend())
        {
            continue;
        }
        out.push_back(ik.first);
        this->list_adjacent_within(ik.first, dist-1, kind, out);
    }
    return;
}

inline void
StructureTopology::construct_chain()
{
    if(this->nodes_.empty()){return;}
    for(auto& node : nodes_)
    {
        node.chain_id = uninitialized();
    }

    std::size_t next_chain_id = 0;
    for(auto& node : nodes_)
    {
//         node.chain_id = uninitialized(); // already set as `uninit`
        for(const auto& edge : node.adjacents)
        {
            if(edge.second == connection_kind_type::contact) {continue;}

            node.chain_id = this->nodes_.at(edge.first).chain_id;
            if(node.chain_id != uninitialized()) {break;}
        }
        if(node.chain_id == uninitialized())
        {
            node.chain_id = next_chain_id++;
        }
    }

    this->num_chains_ = ++next_chain_id;
    return;
}

} // mjolnir
#endif// MJOLNIR_STRUCTURE_TOPOLOGY_H
<|endoftext|>


<commit_before>//
//  LoopInput.cpp
//
// Sketchup C++ Wrapper for C API
// MIT License
//
// Copyright (c) 2017 Tom Kaneko
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//

// Macro for getting rid of unused variables commonly for assert checking
#define _unused(x) ((void)(x))

#include "SUAPI-CppWrapper/model/LoopInput.hpp"

#include <cassert>
#include <iostream>

#include "SUAPI-CppWrapper/Initialize.hpp"
#include "SUAPI-CppWrapper/model/Edge.hpp"
#include "SUAPI-CppWrapper/model/Curve.hpp"
#include "SUAPI-CppWrapper/model/GeometryInput.hpp"
#include "SUAPI-CppWrapper/model/Material.hpp"
#include "SUAPI-CppWrapper/model/Layer.hpp"

namespace CW {

SULoopInputRef LoopInput::create_loop_input_ref() {
  SULoopInputRef loop_input = SU_INVALID;
  SULoopInputCreate(&loop_input);
  return loop_input;
}

/******************************
** Constructors / Destructor **
*******************************/
LoopInput::LoopInput():
  m_loop_input(create_loop_input_ref())
{}

LoopInput::LoopInput(SULoopInputRef loop_input, bool attached):
  m_loop_input(loop_input),
  m_attached(attached)
{}

/*
LoopInput::LoopInput(std::vector<Edge> loop_edges,  size_t vertex_index):
  LoopInput()
{
  for (size_t i=0; i < loop_edges.size(); ++i) {
    add_vertex_index(vertex_index);
    if (SU_API_VERSION_MAJOR >= 5) {
      set_edge_hidden(i, loop_edges[i].hidden());
      set_edge_soft(i, loop_edges[i].soft());
      set_edge_smooth(i, loop_edges[i].smooth());
      Material edge_material = loop_edges[i].material();
      if (!!edge_material) {
        set_edge_material(i, edge_material);
      }
      Layer edge_layer = loop_edges[i].layer();
      if (!!edge_layer) {
        set_edge_layer(i, edge_layer);
      }
    }
    ++vertex_index;
  }
}
*/

LoopInput::LoopInput(const std::vector<InputEdgeProperties>& loop_edge_properties, size_t vertex_index):
  LoopInput()
{
  for (size_t i=0; i < loop_edge_properties.size(); ++i) {
    add_vertex_index(vertex_index);
    if (SU_API_VERSION_MAJOR >= 5) {
      set_edge_hidden(i, loop_edge_properties[i].hidden);
      set_edge_soft(i, loop_edge_properties[i].soft);
      set_edge_smooth(i, loop_edge_properties[i].smooth);
      Material edge_material = loop_edge_properties[i].material;
      if (!!edge_material) {
        set_edge_material(i, edge_material);
      }
      Layer edge_layer = loop_edge_properties[i].layer;
      if (!!edge_layer) {
        set_edge_layer(i, edge_layer);
      }
    }
    ++vertex_index;
  }
}

LoopInput::LoopInput(const LoopInput& other):
  m_loop_input(create_loop_input_ref())
{
  // TODO: Non working method
  // LoopInputRef cannot be copied across at this stage. If it is important, something can be done.
  assert(false && !other);
}

LoopInput::~LoopInput() {
  if (!m_attached && SUIsValid(m_loop_input)) {
    SUResult res = SULoopInputRelease(&m_loop_input);
    assert(res == SU_ERROR_NONE); _unused(res);
  }
}

/*******************
** Public Methods **
********************/
LoopInput& LoopInput::operator=(const LoopInput& other) {
  // There is no easy way to copy a LoopInput object.
  assert(false);
  // Note that this is a crude copying operation - we are simply creating a reference to the other object.
  //m_loop_input = other.m_loop_input;
  /**
  size_t vertex_index = 0;
  SULoopInputRef other_loop_input = other.ref();
  while (SULoopInputEdgeSetHidden(other_loop_input, size_t edge_index, bool hidden))
  */
  return *this; // Temporary return value, to allow compiling on Windows
}

SULoopInputRef LoopInput::ref() const {
  return m_loop_input;
}

LoopInput::operator SULoopInputRef() const {
  return ref();
}

LoopInput::operator SULoopInputRef*() {
  return &m_loop_input;
}

LoopInput::operator bool() const {
  if (SUIsInvalid(m_loop_input)) {
    return false;
  }
  if (m_edge_num > 2) {
    // TODO: this is a little suspect, as m_edge_num is not correct if the LoopInputRef was created before initialising this object.
    return true;
  }
  return false;
}

LoopInput& LoopInput::add_vertex_index(const size_t index) {
  if(!(*this)) {
    throw std::logic_error("CW::LoopInput::add_vertex_index(): LoopInput is null");
  }
  SUResult res = SULoopInputAddVertexIndex(m_loop_input, index);
  assert(res == SU_ERROR_NONE); _unused(res);
  m_edge_num++;
  return (*this);
}

LoopInput& LoopInput::set_edge_hidden(const size_t edge_index, const bool hidden) {
  if(!(*this)) {
    throw std::logic_error("CW::LoopInput::set_edge_hidden(): LoopInput is null");
  }
  SUResult res = SULoopInputEdgeSetHidden(m_loop_input, edge_index, hidden);
  if(res == SU_ERROR_OUT_OF_RANGE) {
    throw std::invalid_argument("CW::LoopInput::set_edge_hidden(): edge_index is larger than the number of vertices in the LoopInput");
  }
  assert(res == SU_ERROR_NONE); _unused(res);
  return (*this);
}

LoopInput& LoopInput::set_edge_soft(const size_t edge_index, const bool soft) {
  if(!(*this)) {
    throw std::logic_error("CW::LoopInput::set_edge_soft(): LoopInput is null");
  }
  SUResult res = SULoopInputEdgeSetSoft(m_loop_input, edge_index, soft);
  if(res == SU_ERROR_OUT_OF_RANGE) {
    throw std::invalid_argument("CW::LoopInput::set_edge_soft(): edge_index is larger than the number of vertices in the LoopInput");
  }
  assert(res == SU_ERROR_NONE); _unused(res);
  return (*this);
}

LoopInput& LoopInput::set_edge_smooth(const size_t edge_index, const bool smooth) {
  if(!(*this)) {
    throw std::logic_error("CW::LoopInput::set_edge_smooth(): LoopInput is null");
  }
  SUResult res = SULoopInputEdgeSetSoft(m_loop_input, edge_index, smooth);
  if(res == SU_ERROR_OUT_OF_RANGE) {
    throw std::invalid_argument("CW::LoopInput::set_edge_smooth(): edge_index is larger than the number of vertices in the LoopInput");
  }
  assert(res == SU_ERROR_NONE); _unused(res);
  return (*this);
}

LoopInput& LoopInput::set_edge_material(const size_t edge_index, const Material& material) {
  if(!(*this)) {
    throw std::logic_error("CW::LoopInput::set_edge_material(): LoopInput is null");
  }
  SUResult res = SULoopInputEdgeSetMaterial(m_loop_input, edge_index, material.ref());
  if(res == SU_ERROR_OUT_OF_RANGE) {
    throw std::invalid_argument("CW::LoopInput::set_edge_material(): edge_index is larger than the number of vertices in the LoopInput");
  }
  assert(res == SU_ERROR_NONE); _unused(res);
  return (*this);}

LoopInput& LoopInput::set_edge_layer(const size_t edge_index, const Layer& layer) {
  if(!(*this)) {
    throw std::logic_error("CW::LoopInput::set_edge_layer(): LoopInput is null");
  }
  SUResult res = SULoopInputEdgeSetLayer(m_loop_input, edge_index, layer.ref());
  if(res == SU_ERROR_OUT_OF_RANGE) {
    throw std::invalid_argument("CW::LoopInput::set_edge_layer(): edge_index is larger than the number of vertices in the LoopInput");
  }
  assert(res == SU_ERROR_NONE); _unused(res);
  return (*this);
}

/*
LoopInput& LoopInput::add_vertices(std::vector<Point3D> points)
{
  for (size_t i=0; i< points.size(); ++i) {
    if (i == (points.size()-1)) {
      m_edges.push_back(Edge(points[i], points[0]));
    }
    else {
      m_edges.push_back(Edge(points[i], points[i+1]));
    }
  }
  return *this;
}
*/

/*
* Adds an edge on the end of the Loop
*/
/*
LoopInput& add_edge(Edge edge);
LoopInput& add_edges(std::vector<Edge> edges);

//LoopInput& add_curve(Curve curve);
//LoopInput& add_curves(std::vector<Curve> curves);
*/

} /* namespace CW */
<commit_msg>Non destructive cleanup of warnings.<commit_after>//
//  LoopInput.cpp
//
// Sketchup C++ Wrapper for C API
// MIT License
//
// Copyright (c) 2017 Tom Kaneko
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//

// Macro for getting rid of unused variables commonly for assert checking
#define _unused(x) ((void)(x))

#include "SUAPI-CppWrapper/model/LoopInput.hpp"

#include <cassert>
#include <iostream>

#include "SUAPI-CppWrapper/Initialize.hpp"
#include "SUAPI-CppWrapper/model/Edge.hpp"
#include "SUAPI-CppWrapper/model/Curve.hpp"
#include "SUAPI-CppWrapper/model/GeometryInput.hpp"
#include "SUAPI-CppWrapper/model/Material.hpp"
#include "SUAPI-CppWrapper/model/Layer.hpp"

namespace CW {

SULoopInputRef LoopInput::create_loop_input_ref() {
  SULoopInputRef loop_input = SU_INVALID;
  SULoopInputCreate(&loop_input);
  return loop_input;
}

/******************************
** Constructors / Destructor **
*******************************/
LoopInput::LoopInput():
  m_loop_input(create_loop_input_ref())
{}

LoopInput::LoopInput(SULoopInputRef loop_input, bool attached):
  m_loop_input(loop_input),
  m_attached(attached)
{}

/*
LoopInput::LoopInput(std::vector<Edge> loop_edges,  size_t vertex_index):
  LoopInput()
{
  for (size_t i=0; i < loop_edges.size(); ++i) {
    add_vertex_index(vertex_index);
    if (SU_API_VERSION_MAJOR >= 5) {
      set_edge_hidden(i, loop_edges[i].hidden());
      set_edge_soft(i, loop_edges[i].soft());
      set_edge_smooth(i, loop_edges[i].smooth());
      Material edge_material = loop_edges[i].material();
      if (!!edge_material) {
        set_edge_material(i, edge_material);
      }
      Layer edge_layer = loop_edges[i].layer();
      if (!!edge_layer) {
        set_edge_layer(i, edge_layer);
      }
    }
    ++vertex_index;
  }
}
*/

LoopInput::LoopInput(const std::vector<InputEdgeProperties>& loop_edge_properties, size_t vertex_index):
  LoopInput()
{
  for (size_t i=0; i < loop_edge_properties.size(); ++i) {
    add_vertex_index(vertex_index);
    if (SU_API_VERSION_MAJOR >= 5) {
      set_edge_hidden(i, loop_edge_properties[i].hidden);
      set_edge_soft(i, loop_edge_properties[i].soft);
      set_edge_smooth(i, loop_edge_properties[i].smooth);
      Material edge_material = loop_edge_properties[i].material;
      if (!!edge_material) {
        set_edge_material(i, edge_material);
      }
      Layer edge_layer = loop_edge_properties[i].layer;
      if (!!edge_layer) {
        set_edge_layer(i, edge_layer);
      }
    }
    ++vertex_index;
  }
}

LoopInput::LoopInput(const LoopInput& other):
  m_loop_input(create_loop_input_ref())
{
  // TODO: Non working method
  // LoopInputRef cannot be copied across at this stage. If it is important, something can be done.
  assert(false && !other);
}

LoopInput::~LoopInput() {
  if (!m_attached && SUIsValid(m_loop_input)) {
    SUResult res = SULoopInputRelease(&m_loop_input);
    assert(res == SU_ERROR_NONE); _unused(res);
  }
}

/*******************
** Public Methods **
********************/
LoopInput& LoopInput::operator=(const LoopInput& other) {
  // TODO: Non working method - the code below is nonesense to escape the warnings
  // There is no easy way to copy a LoopInput object.
  assert(false);
  // Note that this is a crude copying operation - we are simply creating a reference to the other object.
  //m_loop_input = other.m_loop_input;
  /**
  size_t vertex_index = 0;
  SULoopInputRef other_loop_input = other.ref();
  while (SULoopInputEdgeSetHidden(other_loop_input, size_t edge_index, bool hidden))
  */
  return *this; // Temporary return value, to allow compiling on Windows
}

SULoopInputRef LoopInput::ref() const {
  return m_loop_input;
}

LoopInput::operator SULoopInputRef() const {
  return ref();
}

LoopInput::operator SULoopInputRef*() {
  return &m_loop_input;
}

LoopInput::operator bool() const {
  if (SUIsInvalid(m_loop_input)) {
    return false;
  }
  if (m_edge_num > 2) {
    // TODO: this is a little suspect, as m_edge_num is not correct if the LoopInputRef was created before initialising this object.
    return true;
  }
  return false;
}

LoopInput& LoopInput::add_vertex_index(const size_t index) {
  if(!(*this)) {
    throw std::logic_error("CW::LoopInput::add_vertex_index(): LoopInput is null");
  }
  SUResult res = SULoopInputAddVertexIndex(m_loop_input, index);
  assert(res == SU_ERROR_NONE); _unused(res);
  m_edge_num++;
  return (*this);
}

LoopInput& LoopInput::set_edge_hidden(const size_t edge_index, const bool hidden) {
  if(!(*this)) {
    throw std::logic_error("CW::LoopInput::set_edge_hidden(): LoopInput is null");
  }
  SUResult res = SULoopInputEdgeSetHidden(m_loop_input, edge_index, hidden);
  if(res == SU_ERROR_OUT_OF_RANGE) {
    throw std::invalid_argument("CW::LoopInput::set_edge_hidden(): edge_index is larger than the number of vertices in the LoopInput");
  }
  assert(res == SU_ERROR_NONE); _unused(res);
  return (*this);
}

LoopInput& LoopInput::set_edge_soft(const size_t edge_index, const bool soft) {
  if(!(*this)) {
    throw std::logic_error("CW::LoopInput::set_edge_soft(): LoopInput is null");
  }
  SUResult res = SULoopInputEdgeSetSoft(m_loop_input, edge_index, soft);
  if(res == SU_ERROR_OUT_OF_RANGE) {
    throw std::invalid_argument("CW::LoopInput::set_edge_soft(): edge_index is larger than the number of vertices in the LoopInput");
  }
  assert(res == SU_ERROR_NONE); _unused(res);
  return (*this);
}

LoopInput& LoopInput::set_edge_smooth(const size_t edge_index, const bool smooth) {
  if(!(*this)) {
    throw std::logic_error("CW::LoopInput::set_edge_smooth(): LoopInput is null");
  }
  SUResult res = SULoopInputEdgeSetSoft(m_loop_input, edge_index, smooth);
  if(res == SU_ERROR_OUT_OF_RANGE) {
    throw std::invalid_argument("CW::LoopInput::set_edge_smooth(): edge_index is larger than the number of vertices in the LoopInput");
  }
  assert(res == SU_ERROR_NONE); _unused(res);
  return (*this);
}

LoopInput& LoopInput::set_edge_material(const size_t edge_index, const Material& material) {
  if(!(*this)) {
    throw std::logic_error("CW::LoopInput::set_edge_material(): LoopInput is null");
  }
  SUResult res = SULoopInputEdgeSetMaterial(m_loop_input, edge_index, material.ref());
  if(res == SU_ERROR_OUT_OF_RANGE) {
    throw std::invalid_argument("CW::LoopInput::set_edge_material(): edge_index is larger than the number of vertices in the LoopInput");
  }
  assert(res == SU_ERROR_NONE); _unused(res);
  return (*this);}

LoopInput& LoopInput::set_edge_layer(const size_t edge_index, const Layer& layer) {
  if(!(*this)) {
    throw std::logic_error("CW::LoopInput::set_edge_layer(): LoopInput is null");
  }
  SUResult res = SULoopInputEdgeSetLayer(m_loop_input, edge_index, layer.ref());
  if(res == SU_ERROR_OUT_OF_RANGE) {
    throw std::invalid_argument("CW::LoopInput::set_edge_layer(): edge_index is larger than the number of vertices in the LoopInput");
  }
  assert(res == SU_ERROR_NONE); _unused(res);
  return (*this);
}

/*
LoopInput& LoopInput::add_vertices(std::vector<Point3D> points)
{
  for (size_t i=0; i< points.size(); ++i) {
    if (i == (points.size()-1)) {
      m_edges.push_back(Edge(points[i], points[0]));
    }
    else {
      m_edges.push_back(Edge(points[i], points[i+1]));
    }
  }
  return *this;
}
*/

/*
* Adds an edge on the end of the Loop
*/
/*
LoopInput& add_edge(Edge edge);
LoopInput& add_edges(std::vector<Edge> edges);

//LoopInput& add_curve(Curve curve);
//LoopInput& add_curves(std::vector<Curve> curves);
*/

} /* namespace CW */
<|endoftext|>


<commit_before>#ifndef ALLPIX_DEFAULT_DIGITIZER_MODULE_H
#define ALLPIX_DEFAULT_DIGITIZER_MODULE_H

// stl includes
#include <memory>
#include <random>
#include <string>

// include the dependent objects
#include "core/config/Configuration.hpp"
#include "core/messenger/Messenger.hpp"
#include "core/module/Module.hpp"

#include "objects/PixelCharge.hpp"

#include <TH1D.h>

namespace allpix {
    /**
      * @brief Module to simulate digitization of collected charges
      *
      * This module provides a relatively simple simulation of the frontend electronics behavior. It simulates the
     * propagation of the signal of collected charges through the amplifier, comparator and ADC while adding electronics
     * noise and simulating the threshold as well as accounting for threshold dispersion and ADC noise.
      */
    class DefaultDigitizerModule : public Module {
    public:
        /**
           * @brief Constructor for the DefaultDigitizerModule, inheriting from the base class allpix::Module
           * @param config configuration object for this module as retrieved from the steering file
           * @param messenger pointer to the messenger object to allow binding to messages on the bus
       * @param detector pointer to the detector for this module instance
           */
        DefaultDigitizerModule(Configuration config, Messenger* messenger, std::shared_ptr<Detector> detector);

        /**
         * @brief Initialize ROOT histograms and ROOT output file
         */
        void init() override;

        /**
         * @brief Simulate digitization process
         */
        void run(unsigned int) override;

        /**
         * @brief Finalize histogramming and write the to the output file
         */
        void finalize() override;

    private:
        // random generator for this module
        std::mt19937_64 random_generator_;

        // configuration for this module
        Configuration config_;

        // messenger to bind to input message and dispatch output message
        Messenger* messenger_;

        // retrieved message containing collected charges per pixel for a specific detector
        std::shared_ptr<PixelChargeMessage> pixel_message_;

        // statistics
        unsigned long long total_hits_{};

        // Histograms
        TH1D *h_pxq, *h_pxq_noise, *h_thr, *h_pxq_thr, *h_pxq_adc;
    };
} // namespace allpix

#endif /* ALLPIX_DEFAULT_DIGITIZER_MODULE_H */
<commit_msg>fix comment<commit_after>#ifndef ALLPIX_DEFAULT_DIGITIZER_MODULE_H
#define ALLPIX_DEFAULT_DIGITIZER_MODULE_H

// stl includes
#include <memory>
#include <random>
#include <string>

// include the dependent objects
#include "core/config/Configuration.hpp"
#include "core/messenger/Messenger.hpp"
#include "core/module/Module.hpp"

#include "objects/PixelCharge.hpp"

#include <TH1D.h>

namespace allpix {
    /**
      * @brief Module to simulate digitization of collected charges
      *
      * This module provides a relatively simple simulation of the frontend electronics behavior. It simulates the
      * propagation of the signal of collected charges through the amplifier, comparator and ADC while adding electronics
      * noise and simulating the threshold as well as accounting for threshold dispersion and ADC noise.
      */
    class DefaultDigitizerModule : public Module {
    public:
        /**
         * @brief Constructor for the DefaultDigitizerModule, inheriting from the base class allpix::Module
         * @param config configuration object for this module as retrieved from the steering file
         * @param messenger pointer to the messenger object to allow binding to messages on the bus
         * @param detector pointer to the detector for this module instance
         */
        DefaultDigitizerModule(Configuration config, Messenger* messenger, std::shared_ptr<Detector> detector);

        /**
         * @brief Initialize ROOT histograms and ROOT output file
         */
        void init() override;

        /**
         * @brief Simulate digitization process
         */
        void run(unsigned int) override;

        /**
         * @brief Finalize histogramming and write the to the output file
         */
        void finalize() override;

    private:
        // random generator for this module
        std::mt19937_64 random_generator_;

        // configuration for this module
        Configuration config_;

        // messenger to bind to input message and dispatch output message
        Messenger* messenger_;

        // retrieved message containing collected charges per pixel for a specific detector
        std::shared_ptr<PixelChargeMessage> pixel_message_;

        // statistics
        unsigned long long total_hits_{};

        // Histograms
        TH1D *h_pxq, *h_pxq_noise, *h_thr, *h_pxq_thr, *h_pxq_adc;
    };
} // namespace allpix

#endif /* ALLPIX_DEFAULT_DIGITIZER_MODULE_H */
<|endoftext|>


<commit_before>
void ConfigureEMCALRecoUtils(
                             AliEMCALRecoUtils* reco,
                             Bool_t  bMC   = kFALSE,
                             TGeoHMatrix* matrix[10],
                             TString path  = "",
                             Int_t   run   = 0,
                             TString pass  = "pass2"
                             )
{

  // Configure RecoUtils with OADB objects

  printf("**** Configure AliEMCALRecoUtils, LOAD AODB ***\n");
  printf("\t run %d, pass %s\n",run,pass.Data());

  // Exotic cells removal
  reco->SwitchOnRejectExoticCell() ;
  reco->SetExoticCellDiffTimeCut(10000); // Open
  reco->SetExoticCellFractionCut(0.95);  // 1-Ecross/Ecell > 0.95 -> out
  reco->SetExoticCellMinAmplitudeCut(2); // 2 GeV

  gSystem->Load("libOADB");

  // Instantiate EMCAL geometry for the first time

  AliEMCALGeometry*   geom = 0;
  if   (run < 140000) geom = AliEMCALGeometry::GetInstance("EMCAL_FIRSTYEARV1");
  else                geom = AliEMCALGeometry::GetInstance("EMCAL_COMPLETEV1");

  Int_t nSM = geom->GetNumberOfSuperModules();

  // Geometry settings and field

  TGeoManager::Import("geometry.root") ; //need file "geometry.root" in local dir!!!!

  // Put the automatic initialization like in tender somewhere in the clusterizer or reader!!!
  if(run > 140000 && run < 160000)
    TGeoGlobalMagField::Instance()->SetField(new AliMagF("Maps","Maps", -1., -1., AliMagF::k5kG)); // for (--)
  else if(run > 160000)
    TGeoGlobalMagField::Instance()->SetField(new AliMagF("Maps","Maps",  1.,  1., AliMagF::k5kG)); // for (++)
  else if (run < 140000 && run > 138280)
    TGeoGlobalMagField::Instance()->SetField(new AliMagF("Maps","Maps",  1.,  1., AliMagF::k5kG)); // for (++)
  else if (run < 138280 && run > 122000)
    TGeoGlobalMagField::Instance()->SetField(new AliMagF("Maps","Maps", -1., -1., AliMagF::k5kG)); // for (--)
  else if(run > 119100 && run < 122000)
    TGeoGlobalMagField::Instance()->SetField(new AliMagF("Maps","Maps",  1.,  1., AliMagF::k5kG)); // for (++)
  else if(run < 119100 && run > 11900)
    TGeoGlobalMagField::Instance()->SetField(new AliMagF("Maps","Maps",  0.,  0., AliMagF::k5kG)); // for (0)
  else if(run < 119000 && run > 115800)
    TGeoGlobalMagField::Instance()->SetField(new AliMagF("Maps","Maps",  1.,  1., AliMagF::k5kG)); // for (++)
  else if(run < 115800)
    TGeoGlobalMagField::Instance()->SetField(new AliMagF("Maps","Maps", -1., -1., AliMagF::k5kG)); // for (--)

  // Alignment matrices

  TString fileName="$ALICE_ROOT/OADB/EMCAL/EMCALlocal2master.root";
  if(path!="") fileName=path+"EMCALlocal2master.root";

  AliOADBContainer EMCALgeoCont("AliEMCALgeo");
  EMCALgeoCont.InitFromFile((char*)fileName.Data(),"AliEMCALgeo");
  TObjArray *mobj=(TObjArray*)EMCALgeoCont.GetObject(run,"EmcalMatrices");
  for (Int_t mod=0;mod<nSM;mod++)
    {
      matrix[mod] = (TGeoHMatrix*) mobj->At(mod);
      //matrix[mod]->Print();
    }

  reco->SetPositionAlgorithm(AliEMCALRecoUtils::kPosTowerGlobal);

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

  Bool_t bRecal  = kTRUE;
  Bool_t bBad    = kTRUE;
  if(pass == "pass3"){
    bRecal = kFALSE;
    bBad   = kFALSE;
  }

  if(bMC){
    bRecal = kFALSE;
  }

  //Recalibration factors
  if(bRecal){

    fileName="$ALICE_ROOT/OADB/EMCAL/EMCALRecalib.root";
    if(path!="") fileName=path+"EMCALRecalib.root";

    AliOADBContainer *contRF=new AliOADBContainer("");
    contRF->InitFromFile((char*)fileName.Data(),"AliEMCALRecalib");

    TObjArray *recal=(TObjArray*)contRF->GetObject(run);
    if(recal){
      TObjArray *recalpass=(TObjArray*)recal->FindObject(pass);
      if(recalpass){
        TObjArray *recalib=(TObjArray*)recalpass->FindObject("Recalib");
        if(recalib){
          reco->SwitchOnRecalibration();
          printf("AliEMCALRecoUtils - RECALIBRATE \n");
          for (Int_t i=0; i<nSM; ++i) {
            TH2F *h = reco->GetEMCALChannelRecalibrationFactors(i);
            if (h)
              delete h;
            h = (TH2F*)recalib->FindObject(Form("EMCALRecalFactors_SM%d",i));
            if (!h) {
              AliError(Form("Could not load EMCALRecalFactors_SM%d",i));
              continue;
            }
            h->SetDirectory(0);
            reco->SetEMCALChannelRecalibrationFactors(i,h);
          }
        }else printf("AliEMCALRecoUtils ---Do NOT recalibrate 1\n");
      }else printf("AliEMCALRecoUtils ---Do NOT recalibrate 2\n");
    }else printf("AliEMCALRecoUtils ---Do NOT recalibrate 3\n");

    //TFile * f = new TFile("RecalibrationFactors.root","read");
    //for(Int_t i =0; i< 10; i++)  reco->SetEMCALChannelRecalibrationFactors( i, (TH2F*) f->Get(Form("EMCALRecalFactors_SM%d",i)));
    // //  reco->SwitchOnTimeDepCorrection();
    // //  //char cmd[200] ;
    // //  //sprintf(cmd, ".!tar xvfz CorrectionFiles.tgz") ;
    // //  //gROOT->ProcessLine(cmd) ;
    // //

  } else printf("AliEMCALRecoUtils ---Do NOT recalibrate\n");

  // Remove EMCAL hot channels

  if(bBad){

    fileName="$ALICE_ROOT/OADB/EMCAL/EMCALBadChannels.root";
    if(path!="") fileName=path+"EMCALBadChannels.root";

    AliOADBContainer *contBC=new AliOADBContainer("");
    contBC->InitFromFile((char*)fileName.Data(),"AliEMCALBadChannels");
    TObjArray *arrayBC=(TObjArray*)contBC->GetObject(run);
    if(arrayBC){
      TObjArray *arrayBCpass=(TObjArray*)arrayBC->FindObject(pass);
      if(arrayBCpass){

        reco->SwitchOnBadChannelsRemoval();
        reco->SwitchOnDistToBadChannelRecalculation();
        printf("AliEMCALRecoUtils - REMOVE bad cells \n");

        for (Int_t i=0; i<nSM; ++i) {
          TH2I *hbm = reco->GetEMCALChannelStatusMap(i);
          if (hbm)
            delete hbm;
          hbm=(TH2I*)arrayBCpass->FindObject(Form("EMCALBadChannelMap_Mod%d",i));

          if (!hbm) {
            AliError(Form("Can not get EMCALBadChannelMap_Mod%d",i));
            continue;
          }

          hbm->SetDirectory(0);
          reco->SetEMCALChannelStatusMap(i,hbm);
        }
      } else printf("AliEMCALRecoUtils ---Do NOT remove bad channels 1\n");
    }  else printf("AliEMCALRecoUtils ---Do NOT remove bad channels 2\n");
  } else printf("AliEMCALRecoUtils ---Do NOT remove bad channels 3 \n");

  /*
    Int_t iCol = -1, iRow = -1, iSM =-1, iMod = -1,iIphi =-1,iIeta = -1;
    Int_t badAbsID[]={74, 103};

    for(Int_t i=0;i < sizeof(badAbsID)/sizeof(Int_t); i++){
      geom->GetCellIndex(badAbsID[i],iSM,iMod,iIphi,iIeta);
      // Gives SuperModule and Tower numbers
      geom->GetCellPhiEtaIndexInSModule(iSM,iMod,
					iIphi, iIeta,iRow,iCol);
      //printf("bad ID %d, col %d, row %d, sm %d\n",badAbsID[i],iCol,iRow,iSM);
      reco->SetEMCALChannelStatus(iSM , iCol, iRow,1);
    }

    }
   */

  reco->SwitchOnTimeRecalibration();

  //Waiting for OADB, meanwhile

  TFile * ftime = 0;
  //TString path ="./";
  TString path = "alien:///alice/cern.ch/user/g/germain/RecalDB/Time";
  //TGrid::Connect("alien://");

  if     (run > 140000 && run < 146500 )
    ftime = TFile::Open(Form("%s/RefLHC11apass1-7TeV.root",path.Data()));
  else if(run > 146500 && run <= 146860 )
    ftime = TFile::Open(Form("%s/RefLHC11apass3-2.76TeV.root",path.Data()));
  else if(run > 146860 && run < 156477 )
    ftime = TFile::Open(Form("%s/RefLHC11cpass1-7TeV.root",path.Data()));
  else if(run >= 156477)
    ftime = TFile::Open(Form("%s/RefLHC11cpass1-7TeV.root",path.Data()));
  else if(run <  140000 && run > 136850)
    ftime = TFile::Open(Form("%s/RefLHC10hpass2PbPb2.76TeV.root",path.Data()));
  else if(run < 136850)
    ftime = TFile::Open(Form("%s/RefLHC10dpass2-7TeV.root",path.Data()));
  else printf("Run %d, not considered for time calibration\n",run);

  if(ftime){
    printf("AliEMCALRecoUtils - Time recalibration ON\n");

    for(Int_t i =0; i< 4; i++)  reco->SetEMCALChannelTimeRecalibrationFactors( i, (TH1F*) ftime->Get(Form("hAllTimeAvBC%d",i)));
  }
  else printf("AliEMCALRecoUtils --- Time recalibration OFF\n");

}

<commit_msg>correct correction file name for LHC11d period<commit_after>
void ConfigureEMCALRecoUtils(
                             AliEMCALRecoUtils* reco,
                             Bool_t  bMC   = kFALSE,
                             TGeoHMatrix* matrix[10],
                             TString path  = "",
                             Int_t   run   = 0,
                             TString pass  = "pass2"
                             )
{

  // Configure RecoUtils with OADB objects

  printf("**** Configure AliEMCALRecoUtils, LOAD AODB ***\n");
  printf("\t run %d, pass %s\n",run,pass.Data());

  // Exotic cells removal
  reco->SwitchOnRejectExoticCell() ;
  reco->SetExoticCellDiffTimeCut(10000); // Open
  reco->SetExoticCellFractionCut(0.95);  // 1-Ecross/Ecell > 0.95 -> out
  reco->SetExoticCellMinAmplitudeCut(2); // 2 GeV

  gSystem->Load("libOADB");

  // Instantiate EMCAL geometry for the first time

  AliEMCALGeometry*   geom = 0;
  if   (run < 140000) geom = AliEMCALGeometry::GetInstance("EMCAL_FIRSTYEARV1");
  else                geom = AliEMCALGeometry::GetInstance("EMCAL_COMPLETEV1");

  Int_t nSM = geom->GetNumberOfSuperModules();

  // Geometry settings and field

  TGeoManager::Import("geometry.root") ; //need file "geometry.root" in local dir!!!!

  // Put the automatic initialization like in tender somewhere in the clusterizer or reader!!!
  if(run > 140000 && run < 160000)
    TGeoGlobalMagField::Instance()->SetField(new AliMagF("Maps","Maps", -1., -1., AliMagF::k5kG)); // for (--)
  else if(run > 160000)
    TGeoGlobalMagField::Instance()->SetField(new AliMagF("Maps","Maps",  1.,  1., AliMagF::k5kG)); // for (++)
  else if (run < 140000 && run > 138280)
    TGeoGlobalMagField::Instance()->SetField(new AliMagF("Maps","Maps",  1.,  1., AliMagF::k5kG)); // for (++)
  else if (run < 138280 && run > 122000)
    TGeoGlobalMagField::Instance()->SetField(new AliMagF("Maps","Maps", -1., -1., AliMagF::k5kG)); // for (--)
  else if(run > 119100 && run < 122000)
    TGeoGlobalMagField::Instance()->SetField(new AliMagF("Maps","Maps",  1.,  1., AliMagF::k5kG)); // for (++)
  else if(run < 119100 && run > 11900)
    TGeoGlobalMagField::Instance()->SetField(new AliMagF("Maps","Maps",  0.,  0., AliMagF::k5kG)); // for (0)
  else if(run < 119000 && run > 115800)
    TGeoGlobalMagField::Instance()->SetField(new AliMagF("Maps","Maps",  1.,  1., AliMagF::k5kG)); // for (++)
  else if(run < 115800)
    TGeoGlobalMagField::Instance()->SetField(new AliMagF("Maps","Maps", -1., -1., AliMagF::k5kG)); // for (--)

  // Alignment matrices

  TString fileName="$ALICE_ROOT/OADB/EMCAL/EMCALlocal2master.root";
  if(path!="") fileName=path+"EMCALlocal2master.root";

  AliOADBContainer EMCALgeoCont("AliEMCALgeo");
  EMCALgeoCont.InitFromFile((char*)fileName.Data(),"AliEMCALgeo");
  TObjArray *mobj=(TObjArray*)EMCALgeoCont.GetObject(run,"EmcalMatrices");
  for (Int_t mod=0;mod<nSM;mod++)
    {
      matrix[mod] = (TGeoHMatrix*) mobj->At(mod);
      //matrix[mod]->Print();
    }

  reco->SetPositionAlgorithm(AliEMCALRecoUtils::kPosTowerGlobal);

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

  Bool_t bRecal  = kTRUE;
  Bool_t bBad    = kTRUE;
  if(pass == "pass3"){
    bRecal = kFALSE;
    bBad   = kFALSE;
  }

  if(bMC){
    bRecal = kFALSE;
  }

  //Recalibration factors
  if(bRecal){

    fileName="$ALICE_ROOT/OADB/EMCAL/EMCALRecalib.root";
    if(path!="") fileName=path+"EMCALRecalib.root";

    AliOADBContainer *contRF=new AliOADBContainer("");
    contRF->InitFromFile((char*)fileName.Data(),"AliEMCALRecalib");

    TObjArray *recal=(TObjArray*)contRF->GetObject(run);
    if(recal){
      TObjArray *recalpass=(TObjArray*)recal->FindObject(pass);
      if(recalpass){
        TObjArray *recalib=(TObjArray*)recalpass->FindObject("Recalib");
        if(recalib){
          reco->SwitchOnRecalibration();
          printf("AliEMCALRecoUtils - RECALIBRATE \n");
          for (Int_t i=0; i<nSM; ++i) {
            TH2F *h = reco->GetEMCALChannelRecalibrationFactors(i);
            if (h)
              delete h;
            h = (TH2F*)recalib->FindObject(Form("EMCALRecalFactors_SM%d",i));
            if (!h) {
              AliError(Form("Could not load EMCALRecalFactors_SM%d",i));
              continue;
            }
            h->SetDirectory(0);
            reco->SetEMCALChannelRecalibrationFactors(i,h);
          }
        }else printf("AliEMCALRecoUtils ---Do NOT recalibrate 1\n");
      }else printf("AliEMCALRecoUtils ---Do NOT recalibrate 2\n");
    }else printf("AliEMCALRecoUtils ---Do NOT recalibrate 3\n");

    //TFile * f = new TFile("RecalibrationFactors.root","read");
    //for(Int_t i =0; i< 10; i++)  reco->SetEMCALChannelRecalibrationFactors( i, (TH2F*) f->Get(Form("EMCALRecalFactors_SM%d",i)));
    // //  reco->SwitchOnTimeDepCorrection();
    // //  //char cmd[200] ;
    // //  //sprintf(cmd, ".!tar xvfz CorrectionFiles.tgz") ;
    // //  //gROOT->ProcessLine(cmd) ;
    // //

  } else printf("AliEMCALRecoUtils ---Do NOT recalibrate\n");

  // Remove EMCAL hot channels

  if(bBad){

    fileName="$ALICE_ROOT/OADB/EMCAL/EMCALBadChannels.root";
    if(path!="") fileName=path+"EMCALBadChannels.root";

    AliOADBContainer *contBC=new AliOADBContainer("");
    contBC->InitFromFile((char*)fileName.Data(),"AliEMCALBadChannels");
    TObjArray *arrayBC=(TObjArray*)contBC->GetObject(run);
    if(arrayBC){
      TObjArray *arrayBCpass=(TObjArray*)arrayBC->FindObject(pass);
      if(arrayBCpass){

        reco->SwitchOnBadChannelsRemoval();
        reco->SwitchOnDistToBadChannelRecalculation();
        printf("AliEMCALRecoUtils - REMOVE bad cells \n");

        for (Int_t i=0; i<nSM; ++i) {
          TH2I *hbm = reco->GetEMCALChannelStatusMap(i);
          if (hbm)
            delete hbm;
          hbm=(TH2I*)arrayBCpass->FindObject(Form("EMCALBadChannelMap_Mod%d",i));

          if (!hbm) {
            AliError(Form("Can not get EMCALBadChannelMap_Mod%d",i));
            continue;
          }

          hbm->SetDirectory(0);
          reco->SetEMCALChannelStatusMap(i,hbm);
        }
      } else printf("AliEMCALRecoUtils ---Do NOT remove bad channels 1\n");
    }  else printf("AliEMCALRecoUtils ---Do NOT remove bad channels 2\n");
  } else printf("AliEMCALRecoUtils ---Do NOT remove bad channels 3 \n");

  /*
    Int_t iCol = -1, iRow = -1, iSM =-1, iMod = -1,iIphi =-1,iIeta = -1;
    Int_t badAbsID[]={74, 103};

    for(Int_t i=0;i < sizeof(badAbsID)/sizeof(Int_t); i++){
      geom->GetCellIndex(badAbsID[i],iSM,iMod,iIphi,iIeta);
      // Gives SuperModule and Tower numbers
      geom->GetCellPhiEtaIndexInSModule(iSM,iMod,
					iIphi, iIeta,iRow,iCol);
      //printf("bad ID %d, col %d, row %d, sm %d\n",badAbsID[i],iCol,iRow,iSM);
      reco->SetEMCALChannelStatus(iSM , iCol, iRow,1);
    }

    }
   */

  reco->SwitchOnTimeRecalibration();

  //Waiting for OADB, meanwhile

  TFile * ftime = 0;
  //TString path ="./";
  TString path = "alien:///alice/cern.ch/user/g/germain/RecalDB/Time";
  //TGrid::Connect("alien://");

  if     (run > 140000 && run < 146500 )
    ftime = TFile::Open(Form("%s/RefLHC11apass1-7TeV.root",path.Data()));
  else if(run > 146500 && run <= 146860 )
    ftime = TFile::Open(Form("%s/RefLHC11apass3-2.76TeV.root",path.Data()));
  else if(run > 146860 && run < 156477 )
    ftime = TFile::Open(Form("%s/RefLHC11cpass1-7TeV.root",path.Data()));
  else if(run >= 156477)
    ftime = TFile::Open(Form("%s/RefLHC11dpass1-7TeV.root",path.Data()));
  else if(run <  140000 && run > 136850)
    ftime = TFile::Open(Form("%s/RefLHC10hpass2PbPb2.76TeV.root",path.Data()));
  else if(run < 136850)
    ftime = TFile::Open(Form("%s/RefLHC10dpass2-7TeV.root",path.Data()));
  else printf("Run %d, not considered for time calibration\n",run);

  if(ftime){
    printf("AliEMCALRecoUtils - Time recalibration ON\n");

    for(Int_t i =0; i< 4; i++)  reco->SetEMCALChannelTimeRecalibrationFactors( i, (TH1F*) ftime->Get(Form("hAllTimeAvBC%d",i)));
  }
  else printf("AliEMCALRecoUtils --- Time recalibration OFF\n");

}

<|endoftext|>


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

#include "SDIOAnalyzerSettings.h"
#include <AnalyzerHelpers.h>

SDIOAnalyzerSettings::SDIOAnalyzerSettings()
:	mClockChannel( UNDEFINED_CHANNEL ),
	mCmdChannel( UNDEFINED_CHANNEL ),
	mDAT0Channel( UNDEFINED_CHANNEL ),
	mDAT1Channel( UNDEFINED_CHANNEL ),
	mDAT2Channel( UNDEFINED_CHANNEL ),
	mDAT3Channel( UNDEFINED_CHANNEL )
{
	mClockChannelInterface.reset( new AnalyzerSettingInterfaceChannel() );
	mCmdChannelInterface.reset( new AnalyzerSettingInterfaceChannel() );
	mDAT0ChannelInterface.reset( new AnalyzerSettingInterfaceChannel() );
	mDAT1ChannelInterface.reset( new AnalyzerSettingInterfaceChannel() );
	mDAT2ChannelInterface.reset( new AnalyzerSettingInterfaceChannel() );
	mDAT3ChannelInterface.reset( new AnalyzerSettingInterfaceChannel() );

	mClockChannelInterface->SetTitleAndTooltip( "Clock", "Standard SDIO" );
	mCmdChannelInterface->SetTitleAndTooltip( "Command", "Standard SDIO" );
	mDAT0ChannelInterface->SetTitleAndTooltip( "DAT0", "Standard SDIO" );
	mDAT1ChannelInterface->SetTitleAndTooltip( "DAT1", "Standard SDIO" );
	mDAT2ChannelInterface->SetTitleAndTooltip( "DAT2", "Standard SDIO" );
	mDAT3ChannelInterface->SetTitleAndTooltip( "DAT3", "Standard SDIO" );

	mClockChannelInterface->SetChannel( mClockChannel );
	mCmdChannelInterface->SetChannel( mCmdChannel );
	mDAT0ChannelInterface->SetChannel( mDAT0Channel );
	mDAT1ChannelInterface->SetChannel( mDAT1Channel );
	mDAT2ChannelInterface->SetChannel( mDAT2Channel );
	mDAT3ChannelInterface->SetChannel( mDAT3Channel );

	mClockChannelInterface->SetSelectionOfNoneIsAllowed( false );
	mCmdChannelInterface->SetSelectionOfNoneIsAllowed( false );
	mDAT0ChannelInterface->SetSelectionOfNoneIsAllowed( false );
	mDAT1ChannelInterface->SetSelectionOfNoneIsAllowed( true );
	mDAT2ChannelInterface->SetSelectionOfNoneIsAllowed( true );
	mDAT3ChannelInterface->SetSelectionOfNoneIsAllowed( true );

	AddInterface( mClockChannelInterface.get() );
	AddInterface( mCmdChannelInterface.get() );
	AddInterface( mDAT0ChannelInterface.get() );
	AddInterface( mDAT1ChannelInterface.get() );
	AddInterface( mDAT2ChannelInterface.get() );
	AddInterface( mDAT3ChannelInterface.get() );

	AddExportOption( 0, "Export as text/csv file" );
	AddExportExtension( 0, "text", "txt" );
	AddExportExtension( 0, "csv", "csv" );

	ClearChannels();
	// AddChannel( mInputChannel, "Serial", false );
	AddChannel( mClockChannel, "Clock", false );
	AddChannel( mCmdChannel, "Command", false );
	AddChannel( mDAT0Channel, "DAT0", false );
	AddChannel( mDAT1Channel, "DAT1", false );
	AddChannel( mDAT2Channel, "DAT2", false );
	AddChannel( mDAT3Channel, "DAT3", false );
}

SDIOAnalyzerSettings::~SDIOAnalyzerSettings()
{
}

bool SDIOAnalyzerSettings::SetSettingsFromInterfaces()
{
	// mInputChannel = mInputChannelInterface->GetChannel();
	// mBitRate = mBitRateInterface->GetInteger();

	// check channel selection
	{
		Channel d0, d1, d2, d3;
		d0 = mDAT0ChannelInterface->GetChannel();
		d1 = mDAT1ChannelInterface->GetChannel();
		d2 = mDAT2ChannelInterface->GetChannel();
		d3 = mDAT3ChannelInterface->GetChannel();

		if (d1 == UNDEFINED_CHANNEL && d2 == UNDEFINED_CHANNEL && d3 == UNDEFINED_CHANNEL)
		{
			// this is valid, continue
		}
		else if (d1 != UNDEFINED_CHANNEL && d2 != UNDEFINED_CHANNEL && d3 != UNDEFINED_CHANNEL)
		{
			// this is also valid, continue
		}
		else
		{
			// invalid combination
			SetErrorText("Invalid data line selection. If D0 is set, either all or none of the other data lines must be set.");
			return false;
		}
	}

	mClockChannel = mClockChannelInterface->GetChannel();
	mCmdChannel = mCmdChannelInterface->GetChannel();
	mDAT0Channel = mDAT0ChannelInterface->GetChannel();
	mDAT1Channel = mDAT1ChannelInterface->GetChannel();
	mDAT2Channel = mDAT2ChannelInterface->GetChannel();
	mDAT3Channel = mDAT3ChannelInterface->GetChannel();

	ClearChannels();
	// AddChannel( mInputChannel, "SDIO", true );

	AddChannel( mClockChannel, "Clock", true );
	AddChannel( mCmdChannel, "Command", true );
	AddChannel( mDAT0Channel, "DAT0", true );
	AddChannel( mDAT1Channel, "DAT1", mDAT1Channel != UNDEFINED_CHANNEL);
	AddChannel( mDAT2Channel, "DAT2", mDAT2Channel != UNDEFINED_CHANNEL);
	AddChannel( mDAT3Channel, "DAT3", mDAT3Channel != UNDEFINED_CHANNEL);
	return true;
}

void SDIOAnalyzerSettings::UpdateInterfacesFromSettings()
{
	// mInputChannelInterface->SetChannel( mInputChannel );
	// mBitRateInterface->SetInteger( mBitRate );
	mClockChannelInterface->SetChannel( mClockChannel );
	mCmdChannelInterface->SetChannel( mCmdChannel );
	mDAT0ChannelInterface->SetChannel( mDAT0Channel );
	mDAT1ChannelInterface->SetChannel( mDAT1Channel );
	mDAT2ChannelInterface->SetChannel( mDAT2Channel );
	mDAT3ChannelInterface->SetChannel( mDAT3Channel );
}

void SDIOAnalyzerSettings::LoadSettings( const char* settings )
{
	SimpleArchive text_archive;
	text_archive.SetString( settings );

	text_archive >> mClockChannel;
	text_archive >> mCmdChannel;
	text_archive >> mDAT0Channel;
	text_archive >> mDAT1Channel;
	text_archive >> mDAT2Channel;
	text_archive >> mDAT3Channel;

	ClearChannels();

	AddChannel( mClockChannel, "Clock", true );
	AddChannel( mCmdChannel, "Cmd", true );
	AddChannel( mDAT0Channel, "DAT0", true );
	AddChannel( mDAT1Channel, "DAT1", mDAT1Channel != UNDEFINED_CHANNEL);
	AddChannel( mDAT2Channel, "DAT2", mDAT2Channel != UNDEFINED_CHANNEL);
	AddChannel( mDAT3Channel, "DAT3", mDAT3Channel != UNDEFINED_CHANNEL);

	UpdateInterfacesFromSettings();
}

const char* SDIOAnalyzerSettings::SaveSettings()
{
	SimpleArchive text_archive;

	text_archive << mClockChannel;
	text_archive << mCmdChannel;
	text_archive << mDAT0Channel;
	text_archive << mDAT1Channel;
	text_archive << mDAT2Channel;
	text_archive << mDAT3Channel;
	// text_archive << mInputChannel;
	// text_archive << mBitRate;

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

#include "SDIOAnalyzerSettings.h"
#include <AnalyzerHelpers.h>

SDIOAnalyzerSettings::SDIOAnalyzerSettings()
:	mClockChannel( UNDEFINED_CHANNEL ),
	mCmdChannel( UNDEFINED_CHANNEL ),
	mDAT0Channel( UNDEFINED_CHANNEL ),
	mDAT1Channel( UNDEFINED_CHANNEL ),
	mDAT2Channel( UNDEFINED_CHANNEL ),
	mDAT3Channel( UNDEFINED_CHANNEL )
{
	mClockChannelInterface.reset( new AnalyzerSettingInterfaceChannel() );
	mCmdChannelInterface.reset( new AnalyzerSettingInterfaceChannel() );
	mDAT0ChannelInterface.reset( new AnalyzerSettingInterfaceChannel() );
	mDAT1ChannelInterface.reset( new AnalyzerSettingInterfaceChannel() );
	mDAT2ChannelInterface.reset( new AnalyzerSettingInterfaceChannel() );
	mDAT3ChannelInterface.reset( new AnalyzerSettingInterfaceChannel() );

	mClockChannelInterface->SetTitleAndTooltip( "Clock", "Standard SDIO" );
	mCmdChannelInterface->SetTitleAndTooltip( "Command", "Standard SDIO" );
	mDAT0ChannelInterface->SetTitleAndTooltip( "DAT0", "Standard SDIO" );
	mDAT1ChannelInterface->SetTitleAndTooltip( "DAT1", "Standard SDIO" );
	mDAT2ChannelInterface->SetTitleAndTooltip( "DAT2", "Standard SDIO" );
	mDAT3ChannelInterface->SetTitleAndTooltip( "DAT3", "Standard SDIO" );

	mClockChannelInterface->SetChannel( mClockChannel );
	mCmdChannelInterface->SetChannel( mCmdChannel );
	mDAT0ChannelInterface->SetChannel( mDAT0Channel );
	mDAT1ChannelInterface->SetChannel( mDAT1Channel );
	mDAT2ChannelInterface->SetChannel( mDAT2Channel );
	mDAT3ChannelInterface->SetChannel( mDAT3Channel );

	mClockChannelInterface->SetSelectionOfNoneIsAllowed( false );
	mCmdChannelInterface->SetSelectionOfNoneIsAllowed( false );
	mDAT0ChannelInterface->SetSelectionOfNoneIsAllowed( false );
	mDAT1ChannelInterface->SetSelectionOfNoneIsAllowed( true );
	mDAT2ChannelInterface->SetSelectionOfNoneIsAllowed( true );
	mDAT3ChannelInterface->SetSelectionOfNoneIsAllowed( true );

	AddInterface( mClockChannelInterface.get() );
	AddInterface( mCmdChannelInterface.get() );
	AddInterface( mDAT0ChannelInterface.get() );
	AddInterface( mDAT1ChannelInterface.get() );
	AddInterface( mDAT2ChannelInterface.get() );
	AddInterface( mDAT3ChannelInterface.get() );

	AddExportOption( 0, "Export as text/csv file" );
	AddExportExtension( 0, "text", "txt" );
	AddExportExtension( 0, "csv", "csv" );

	ClearChannels();
	// AddChannel( mInputChannel, "Serial", false );
	AddChannel( mClockChannel, "Clock", false );
	AddChannel( mCmdChannel, "Command", false );
	AddChannel( mDAT0Channel, "DAT0", false );
	AddChannel( mDAT1Channel, "DAT1", false );
	AddChannel( mDAT2Channel, "DAT2", false );
	AddChannel( mDAT3Channel, "DAT3", false );
}

SDIOAnalyzerSettings::~SDIOAnalyzerSettings()
{
}

bool SDIOAnalyzerSettings::SetSettingsFromInterfaces()
{
	// mInputChannel = mInputChannelInterface->GetChannel();
	// mBitRate = mBitRateInterface->GetInteger();

	// check channel selection
	{
		Channel d0, d1, d2, d3;
		d0 = mDAT0ChannelInterface->GetChannel();
		d1 = mDAT1ChannelInterface->GetChannel();
		d2 = mDAT2ChannelInterface->GetChannel();
		d3 = mDAT3ChannelInterface->GetChannel();

		if (d1 == UNDEFINED_CHANNEL && d2 == UNDEFINED_CHANNEL && d3 == UNDEFINED_CHANNEL)
		{
			// this is valid, continue
		}
		else if (d1 != UNDEFINED_CHANNEL && d2 != UNDEFINED_CHANNEL && d3 != UNDEFINED_CHANNEL)
		{
			// this is also valid, continue
		}
		else
		{
			// invalid combination
			SetErrorText("Invalid data line selection. If D0 is set, either all or none of the other data lines must be set.");
			return false;
		}

		std::vector<Channel> channels;
		channels.push_back(d0);
		channels.push_back(d1);
		channels.push_back(d2);
		channels.push_back(d3);
		channels.push_back(mClockChannelInterface->GetChannel());
		channels.push_back(mCmdChannelInterface->GetChannel());

		if (AnalyzerHelpers::DoChannelsOverlap(channels.data(), channels.size()) == true)
		{
			SetErrorText("Channel selections must be unique");
			return false;
		}
	}

	mClockChannel = mClockChannelInterface->GetChannel();
	mCmdChannel = mCmdChannelInterface->GetChannel();
	mDAT0Channel = mDAT0ChannelInterface->GetChannel();
	mDAT1Channel = mDAT1ChannelInterface->GetChannel();
	mDAT2Channel = mDAT2ChannelInterface->GetChannel();
	mDAT3Channel = mDAT3ChannelInterface->GetChannel();

	ClearChannels();
	// AddChannel( mInputChannel, "SDIO", true );

	AddChannel( mClockChannel, "Clock", true );
	AddChannel( mCmdChannel, "Command", true );
	AddChannel( mDAT0Channel, "DAT0", true );
	AddChannel( mDAT1Channel, "DAT1", mDAT1Channel != UNDEFINED_CHANNEL);
	AddChannel( mDAT2Channel, "DAT2", mDAT2Channel != UNDEFINED_CHANNEL);
	AddChannel( mDAT3Channel, "DAT3", mDAT3Channel != UNDEFINED_CHANNEL);
	return true;
}

void SDIOAnalyzerSettings::UpdateInterfacesFromSettings()
{
	// mInputChannelInterface->SetChannel( mInputChannel );
	// mBitRateInterface->SetInteger( mBitRate );
	mClockChannelInterface->SetChannel( mClockChannel );
	mCmdChannelInterface->SetChannel( mCmdChannel );
	mDAT0ChannelInterface->SetChannel( mDAT0Channel );
	mDAT1ChannelInterface->SetChannel( mDAT1Channel );
	mDAT2ChannelInterface->SetChannel( mDAT2Channel );
	mDAT3ChannelInterface->SetChannel( mDAT3Channel );
}

void SDIOAnalyzerSettings::LoadSettings( const char* settings )
{
	SimpleArchive text_archive;
	text_archive.SetString( settings );

	text_archive >> mClockChannel;
	text_archive >> mCmdChannel;
	text_archive >> mDAT0Channel;
	text_archive >> mDAT1Channel;
	text_archive >> mDAT2Channel;
	text_archive >> mDAT3Channel;

	ClearChannels();

	AddChannel( mClockChannel, "Clock", true );
	AddChannel( mCmdChannel, "Cmd", true );
	AddChannel( mDAT0Channel, "DAT0", true );
	AddChannel( mDAT1Channel, "DAT1", mDAT1Channel != UNDEFINED_CHANNEL);
	AddChannel( mDAT2Channel, "DAT2", mDAT2Channel != UNDEFINED_CHANNEL);
	AddChannel( mDAT3Channel, "DAT3", mDAT3Channel != UNDEFINED_CHANNEL);

	UpdateInterfacesFromSettings();
}

const char* SDIOAnalyzerSettings::SaveSettings()
{
	SimpleArchive text_archive;

	text_archive << mClockChannel;
	text_archive << mCmdChannel;
	text_archive << mDAT0Channel;
	text_archive << mDAT1Channel;
	text_archive << mDAT2Channel;
	text_archive << mDAT3Channel;
	// text_archive << mInputChannel;
	// text_archive << mBitRate;

	return SetReturnString( text_archive.GetString() );
}
<|endoftext|>