<commit_before>#ifndef STAN_MATH_OPENCL_KERNEL_CL_HPP
#define STAN_MATH_OPENCL_KERNEL_CL_HPP
#ifdef STAN_OPENCL

#include <stan/math/opencl/buffer_types.hpp>
#include <stan/math/opencl/matrix_cl_view.hpp>
#include <stan/math/opencl/opencl_context.hpp>
#include <stan/math/opencl/matrix_cl.hpp>
#include <stan/math/opencl/stringify.hpp>
#include <stan/math/opencl/err/check_opencl.hpp>
#include <stan/math/opencl/kernels/helpers.hpp>
#include <stan/math/prim/fun/vec_concat.hpp>
#include <CL/cl2.hpp>
#include <algorithm>
#include <map>
#include <string>
#include <vector>
#include <utility>

namespace stan {
namespace math {
namespace opencl_kernels {
namespace internal {
/** \ingroup kernel_executor_opencl
 * Extracts the kernel's arguments, used in the global and local kernel
 * constructor.
 * @tparam For this general template the function will return back the
 * value passed in.
 * @param t The type that will be returned.
 * @return the input t.
 */
template <typename T, typename K = double>
inline const T& get_kernel_args(const T& t) {
  return t;
}

/** \ingroup kernel_executor_opencl
 * Extracts the kernel's arguments, used in the global and local kernel
 * constructor.
 * @tparam K The type of the \c matrix_cl.
 * @param m The \c matrix with an OpenCL Buffer.
 * @return The OpenCL Buffer.
 */
template <typename K>
inline const cl::Buffer& get_kernel_args(const stan::math::matrix_cl<K>& m) {
  return m.buffer();
}

/** \ingroup kernel_executor_opencl
 * Helper function for assigning events to a \c matrix_cl.
 *
 * @tparam T Whether the assignment is to an \c in_buffer, \c out_buffer, or \c
 * in_out_buffer.
 * @tparam K The type of the \c matrix_cl.
 *
 */
template <typename T, typename K = double>
struct assign_event_helper {
  /** \ingroup kernel_executor_opencl
   * Assigns the event to the \c matrix_cl.
   * @param e the event to be assigned.
   * @param m The \c matrix_cl to be assigned to.
   */
  inline void set(const cl::Event& e, const stan::math::matrix_cl<K>& m) {}
};

// Specialization for \c in_buffer
template <typename K>
struct assign_event_helper<in_buffer, K> {
  inline void set(const cl::Event& e, const stan::math::matrix_cl<K>& m) {
    m.add_read_event(e);
  }
};

// Specialization for \c out_buffer
template <typename K>
struct assign_event_helper<out_buffer, K> {
  inline void set(const cl::Event& e, const stan::math::matrix_cl<K>& m) {
    m.add_write_event(e);
  }
};

// Specialization for \c in_out_buffer
template <typename K>
struct assign_event_helper<in_out_buffer, K> {
  inline void set(const cl::Event& e, const stan::math::matrix_cl<K>& m) {
    m.add_read_write_event(e);
  }
};

/** \ingroup kernel_executor_opencl
 * Assigns the event to a \c matrix_cl.
 * @tparam T The type to be assigned, if not a matrix_cl this function
 * will do nothing.
 * @tparam K The type of the \c matrix_cl.
 * @param e The event to be assigned.
 */
template <typename T, typename K = double>
inline void assign_event(const cl::Event& e, const T&) {}

/** \ingroup kernel_executor_opencl
 * Assigns the event to a \c matrix_cl
 * @tparam T The type to be assigned, if not a matrix_cl will do nothing.
 * @tparam K The type of the \c matrix_cl.
 * @param e The event to be assigned.
 * @param m The \c matrix_cl to be assigned
 */
template <typename T, typename K>
inline void assign_event(const cl::Event& e,
                         const stan::math::matrix_cl<K>& m) {
  assign_event_helper<T, K> helper;
  helper.set(e, m);
}

template <typename T, require_same_t<T, cl::Event>* = nullptr>
inline void assign_events(const T&) {}

/** \ingroup kernel_executor_opencl
 * Adds the event to any \c matrix_cls in the arguments depending on whether
 * they are \c in_buffer, \c out_buffer, or \c in_out_buffers.
 * @tparam Arg Arguments given during kernel creation that specify the kernel
 * signature.
 * @tparam Args Arguments given during kernel creation that specify the kernel
 * signature.
 * @tparam CallArg First argument type used to call the kernel
 * @tparam CallArgs Other argument types used to call the kernel.
 * @param new_event The cl::Event generated involving the arguments.
 * @param m Arguments to the kernel that may be \c matrix_cls or not.
 * Non-matrices are ignored.
 * @param args Arguments to the kernel that may be matrices or not.
 * Non-matrices are ignored.
 */
template <typename Arg, typename... Args, typename CallArg,
          typename... CallArgs>
inline void assign_events(const cl::Event& new_event, CallArg& m,
                          CallArgs&... args) {
  assign_event<Arg>(new_event, m);
  assign_events<Args...>(new_event, args...);
}

/** \ingroup kernel_executor_opencl
 * Helper function to select OpenCL event vectors from an \c matrix_cl
 * @tparam T For non \c matrix_cl types, the type of the first argument.
 * Otherwise this is the in/out/inout buffer type.
 * @tparam K For \c matrix_cl types, the type of the matrix_cl
 */
template <typename T, typename K = double>
struct select_event_helper {
  /** \ingroup kernel_executor_opencl
   * Get the events from a matrix_cl. For non \c matrix_cl types this will do
   * nothing.
   * @param m A type to extract the event from.
   */
  inline const std::vector<cl::Event> get(const T& m) {
    return std::vector<cl::Event>();
  }
};

// Specialization for in_buffer
template <typename K>
struct select_event_helper<in_buffer, K> {
  inline const std::vector<cl::Event> get(const stan::math::matrix_cl<K>& m) {
    return m.write_events();
  }
};

// Specialization for out_buffer
template <typename K>
struct select_event_helper<out_buffer, K> {
  inline const std::vector<cl::Event> get(const stan::math::matrix_cl<K>& m) {
    return m.read_write_events();
  }
};

// Specialization for in_out_buffer
template <typename K>
struct select_event_helper<in_out_buffer, K> {
  inline const std::vector<cl::Event> get(const stan::math::matrix_cl<K>& m) {
    return m.read_write_events();
  }
};

/** \ingroup kernel_executor_opencl
 * Select events from kernel arguments. Does nothing for non \c matrix_cl types.
 * @tparam T The argument type for a non \c matrix_cl, else the in/out/in_out
 * buffer types.
 * @tparam K The type of the \c matrix_cl
 * @param m If an \c matrix_cl, gets the event vector, else this argument does
 * nothing.
 * @return A vector of OpenCL events.
 */
template <typename T, typename K = double>
inline const std::vector<cl::Event> select_events(const T& m) {
  select_event_helper<T, K> helper;
  return helper.get(m);
}

// Specialization for \c matrix_cl
template <typename T, typename K>
inline const std::vector<cl::Event> select_events(
    const stan::math::matrix_cl<K>& m) {
  select_event_helper<T, K> helper;
  return helper.get(m);
}

}  // namespace internal

/** \ingroup kernel_executor_opencl
 * Compile an OpenCL kernel.
 *
 * @param name The name for the kernel
 * @param sources A std::vector of strings containing the code for the kernel.
 * @param options The values of macros to be passed at compile time.
 */
inline auto compile_kernel(const char* name,
                           const std::vector<std::string>& sources,
                           const std::map<std::string, int>& options) {
  auto base_opts = opencl_context.base_opts();
  for (auto& it : options) {
    if (base_opts[it.first] > it.second) {
      base_opts[it.first] = it.second;
    }
  }
  std::string kernel_opts = "";
  for (auto&& comp_opts : base_opts) {
    kernel_opts += std::string(" -D") + comp_opts.first + "="
                   + std::to_string(comp_opts.second);
  }
  cl::Program program(opencl_context.context(), sources);
  try {
    program.build({opencl_context.device()}, kernel_opts.c_str());

    return cl::Kernel(program, name);
  } catch (const cl::Error& e) {
    // in case of CL_BUILD_PROGRAM_FAILURE, print the build error
    if (e.err() == -11) {
      std::string buildlog = program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(
          opencl_context.device()[0]);
      system_error("compile_kernel", name, e.err(), buildlog.c_str());
    } else {
      check_opencl_error(name, e);
    }
  }
  return cl::Kernel();  // never reached because check_opencl_error throws
}

/** \ingroup kernel_executor_opencl
 * Creates functor for kernels
 *
 * @tparam Args Parameter pack of all kernel argument types.
 */
template <typename... Args>
struct kernel_cl {
 private:
  const char* name_;
  std::vector<std::string> sources_;
  std::map<std::string, int> opts_;
  mutable cl::Kernel kernel_;

 public:
  /** \ingroup kernel_executor_opencl
   * Creates functor for kernels that only need access to defining
   *  the global work size.
   * @param name The name for the kernel
   * @param sources A std::vector of strings containing the code for the kernel.
   * @param options The values of macros to be passed at compile time.
   */
  kernel_cl(const char* name, std::vector<std::string> sources,
            std::map<std::string, int> options = {})
      : name_(name), sources_(std::move(sources)), opts_(std::move(options)) {}

  /** \ingroup kernel_executor_opencl
   * Executes a kernel
   * @tparam CallArgs The types of the callee arguments.
   * @tparam Args Parameter pack of all kernel argument types.
   * @param global_thread_size The global work size.
   * @param args The arguments to pass to the kernel.
   * @return An Opencl event.
   */
  template <typename... CallArgs>
  auto operator()(cl::NDRange global_thread_size,
                  const CallArgs&... args) const {
    if (kernel_() == NULL) {
      kernel_ = compile_kernel(name_, sources_, opts_);
      opencl_context.register_kernel_cache(&kernel_);
    }
    cl::EnqueueArgs eargs(opencl_context.queue(),
                          vec_concat(internal::select_events<Args>(args)...),
                          global_thread_size);
    cl::KernelFunctor<internal::to_const_buffer_t<Args>&...> kernel_functor(
        kernel_);
    cl::Event kern_event
        = kernel_functor(eargs, internal::get_kernel_args(args)...);
    internal::assign_events<Args...>(kern_event, args...);
    return kern_event;
  }

  /** \ingroup kernel_executor_opencl
   * Executes a kernel
   * @tparam CallArgs The types of the callee arguments.
   * @tparam Args Parameter pack of all kernel argument types.
   * @param global_thread_size The global work size.
   * @param thread_block_size The thread block size.
   * @param args The arguments to pass to the kernel.
   * @return An Opencl event.
   */
  template <typename... CallArgs>
  auto operator()(cl::NDRange global_thread_size, cl::NDRange thread_block_size,
                  const CallArgs&... args) const {
    if (kernel_() == NULL) {
      kernel_ = compile_kernel(name_, sources_, opts_);
      opencl_context.register_kernel_cache(&kernel_);
    }
    cl::EnqueueArgs eargs(opencl_context.queue(),
                          vec_concat(internal::select_events<Args>(args)...),
                          global_thread_size, thread_block_size);
    cl::KernelFunctor<internal::to_const_buffer_t<Args>&...> kernel_functor(
        kernel_);
    cl::Event kern_event
        = kernel_functor(eargs, internal::get_kernel_args(args)...);
    internal::assign_events<Args...>(kern_event, args...);
    return kern_event;
  }

  /** \ingroup kernel_executor_opencl
   * Retrieves an option used for compiling the kernel.
   * @param option_name which option to retrieve
   * @return option value
   */
  int get_option(const std::string option_name) const {
    return opts_.at(option_name);
  }
};

}  // namespace opencl_kernels
}  // namespace math
}  // namespace stan

#endif
#endif
<commit_msg>bugfixed merging of kernel and base options<commit_after>#ifndef STAN_MATH_OPENCL_KERNEL_CL_HPP
#define STAN_MATH_OPENCL_KERNEL_CL_HPP
#ifdef STAN_OPENCL

#include <stan/math/opencl/buffer_types.hpp>
#include <stan/math/opencl/matrix_cl_view.hpp>
#include <stan/math/opencl/opencl_context.hpp>
#include <stan/math/opencl/matrix_cl.hpp>
#include <stan/math/opencl/stringify.hpp>
#include <stan/math/opencl/err/check_opencl.hpp>
#include <stan/math/opencl/kernels/helpers.hpp>
#include <stan/math/prim/fun/vec_concat.hpp>
#include <CL/cl2.hpp>
#include <algorithm>
#include <map>
#include <string>
#include <vector>
#include <utility>

namespace stan {
namespace math {
namespace opencl_kernels {
namespace internal {
/** \ingroup kernel_executor_opencl
 * Extracts the kernel's arguments, used in the global and local kernel
 * constructor.
 * @tparam For this general template the function will return back the
 * value passed in.
 * @param t The type that will be returned.
 * @return the input t.
 */
template <typename T, typename K = double>
inline const T& get_kernel_args(const T& t) {
  return t;
}

/** \ingroup kernel_executor_opencl
 * Extracts the kernel's arguments, used in the global and local kernel
 * constructor.
 * @tparam K The type of the \c matrix_cl.
 * @param m The \c matrix with an OpenCL Buffer.
 * @return The OpenCL Buffer.
 */
template <typename K>
inline const cl::Buffer& get_kernel_args(const stan::math::matrix_cl<K>& m) {
  return m.buffer();
}

/** \ingroup kernel_executor_opencl
 * Helper function for assigning events to a \c matrix_cl.
 *
 * @tparam T Whether the assignment is to an \c in_buffer, \c out_buffer, or \c
 * in_out_buffer.
 * @tparam K The type of the \c matrix_cl.
 *
 */
template <typename T, typename K = double>
struct assign_event_helper {
  /** \ingroup kernel_executor_opencl
   * Assigns the event to the \c matrix_cl.
   * @param e the event to be assigned.
   * @param m The \c matrix_cl to be assigned to.
   */
  inline void set(const cl::Event& e, const stan::math::matrix_cl<K>& m) {}
};

// Specialization for \c in_buffer
template <typename K>
struct assign_event_helper<in_buffer, K> {
  inline void set(const cl::Event& e, const stan::math::matrix_cl<K>& m) {
    m.add_read_event(e);
  }
};

// Specialization for \c out_buffer
template <typename K>
struct assign_event_helper<out_buffer, K> {
  inline void set(const cl::Event& e, const stan::math::matrix_cl<K>& m) {
    m.add_write_event(e);
  }
};

// Specialization for \c in_out_buffer
template <typename K>
struct assign_event_helper<in_out_buffer, K> {
  inline void set(const cl::Event& e, const stan::math::matrix_cl<K>& m) {
    m.add_read_write_event(e);
  }
};

/** \ingroup kernel_executor_opencl
 * Assigns the event to a \c matrix_cl.
 * @tparam T The type to be assigned, if not a matrix_cl this function
 * will do nothing.
 * @tparam K The type of the \c matrix_cl.
 * @param e The event to be assigned.
 */
template <typename T, typename K = double>
inline void assign_event(const cl::Event& e, const T&) {}

/** \ingroup kernel_executor_opencl
 * Assigns the event to a \c matrix_cl
 * @tparam T The type to be assigned, if not a matrix_cl will do nothing.
 * @tparam K The type of the \c matrix_cl.
 * @param e The event to be assigned.
 * @param m The \c matrix_cl to be assigned
 */
template <typename T, typename K>
inline void assign_event(const cl::Event& e,
                         const stan::math::matrix_cl<K>& m) {
  assign_event_helper<T, K> helper;
  helper.set(e, m);
}

template <typename T, require_same_t<T, cl::Event>* = nullptr>
inline void assign_events(const T&) {}

/** \ingroup kernel_executor_opencl
 * Adds the event to any \c matrix_cls in the arguments depending on whether
 * they are \c in_buffer, \c out_buffer, or \c in_out_buffers.
 * @tparam Arg Arguments given during kernel creation that specify the kernel
 * signature.
 * @tparam Args Arguments given during kernel creation that specify the kernel
 * signature.
 * @tparam CallArg First argument type used to call the kernel
 * @tparam CallArgs Other argument types used to call the kernel.
 * @param new_event The cl::Event generated involving the arguments.
 * @param m Arguments to the kernel that may be \c matrix_cls or not.
 * Non-matrices are ignored.
 * @param args Arguments to the kernel that may be matrices or not.
 * Non-matrices are ignored.
 */
template <typename Arg, typename... Args, typename CallArg,
          typename... CallArgs>
inline void assign_events(const cl::Event& new_event, CallArg& m,
                          CallArgs&... args) {
  assign_event<Arg>(new_event, m);
  assign_events<Args...>(new_event, args...);
}

/** \ingroup kernel_executor_opencl
 * Helper function to select OpenCL event vectors from an \c matrix_cl
 * @tparam T For non \c matrix_cl types, the type of the first argument.
 * Otherwise this is the in/out/inout buffer type.
 * @tparam K For \c matrix_cl types, the type of the matrix_cl
 */
template <typename T, typename K = double>
struct select_event_helper {
  /** \ingroup kernel_executor_opencl
   * Get the events from a matrix_cl. For non \c matrix_cl types this will do
   * nothing.
   * @param m A type to extract the event from.
   */
  inline const std::vector<cl::Event> get(const T& m) {
    return std::vector<cl::Event>();
  }
};

// Specialization for in_buffer
template <typename K>
struct select_event_helper<in_buffer, K> {
  inline const std::vector<cl::Event> get(const stan::math::matrix_cl<K>& m) {
    return m.write_events();
  }
};

// Specialization for out_buffer
template <typename K>
struct select_event_helper<out_buffer, K> {
  inline const std::vector<cl::Event> get(const stan::math::matrix_cl<K>& m) {
    return m.read_write_events();
  }
};

// Specialization for in_out_buffer
template <typename K>
struct select_event_helper<in_out_buffer, K> {
  inline const std::vector<cl::Event> get(const stan::math::matrix_cl<K>& m) {
    return m.read_write_events();
  }
};

/** \ingroup kernel_executor_opencl
 * Select events from kernel arguments. Does nothing for non \c matrix_cl types.
 * @tparam T The argument type for a non \c matrix_cl, else the in/out/in_out
 * buffer types.
 * @tparam K The type of the \c matrix_cl
 * @param m If an \c matrix_cl, gets the event vector, else this argument does
 * nothing.
 * @return A vector of OpenCL events.
 */
template <typename T, typename K = double>
inline const std::vector<cl::Event> select_events(const T& m) {
  select_event_helper<T, K> helper;
  return helper.get(m);
}

// Specialization for \c matrix_cl
template <typename T, typename K>
inline const std::vector<cl::Event> select_events(
    const stan::math::matrix_cl<K>& m) {
  select_event_helper<T, K> helper;
  return helper.get(m);
}

}  // namespace internal

/** \ingroup kernel_executor_opencl
 * Compile an OpenCL kernel.
 *
 * @param name The name for the kernel
 * @param sources A std::vector of strings containing the code for the kernel.
 * @param options The values of macros to be passed at compile time.
 */
inline auto compile_kernel(const char* name,
                           const std::vector<std::string>& sources,
                           const std::map<std::string, int>& options) {
  std::string kernel_opts = "";
  for (auto&& comp_opts : options) {
    kernel_opts += std::string(" -D") + comp_opts.first + "="
                   + std::to_string(comp_opts.second);
  }
  cl::Program program(opencl_context.context(), sources);
  try {
    program.build({opencl_context.device()}, kernel_opts.c_str());

    return cl::Kernel(program, name);
  } catch (const cl::Error& e) {
    // in case of CL_BUILD_PROGRAM_FAILURE, print the build error
    if (e.err() == -11) {
      std::string buildlog = program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(
          opencl_context.device()[0]);
      system_error("compile_kernel", name, e.err(), buildlog.c_str());
    } else {
      check_opencl_error(name, e);
    }
  }
  return cl::Kernel();  // never reached because check_opencl_error throws
}

/** \ingroup kernel_executor_opencl
 * Creates functor for kernels
 *
 * @tparam Args Parameter pack of all kernel argument types.
 */
template <typename... Args>
struct kernel_cl {
 private:
  const char* name_;
  std::vector<std::string> sources_;
  std::map<std::string, int> opts_;
  mutable cl::Kernel kernel_;

 public:
  /** \ingroup kernel_executor_opencl
   * Creates functor for kernels that only need access to defining
   *  the global work size.
   * @param name The name for the kernel
   * @param sources A std::vector of strings containing the code for the kernel.
   * @param options The values of macros to be passed at compile time.
   */
  kernel_cl(const char* name, std::vector<std::string> sources,
            std::map<std::string, int> options = {})
      : name_(name), sources_(std::move(sources)), opts_(opencl_context.base_opts()) {
    for (auto& it : options) {
      if (opts_[it.first] > it.second) {
        opts_[it.first] = it.second;
      }
    }
  }

  /** \ingroup kernel_executor_opencl
   * Executes a kernel
   * @tparam CallArgs The types of the callee arguments.
   * @tparam Args Parameter pack of all kernel argument types.
   * @param global_thread_size The global work size.
   * @param args The arguments to pass to the kernel.
   * @return An Opencl event.
   */
  template <typename... CallArgs>
  auto operator()(cl::NDRange global_thread_size,
                  const CallArgs&... args) const {
    if (kernel_() == NULL) {
      kernel_ = compile_kernel(name_, sources_, opts_);
      opencl_context.register_kernel_cache(&kernel_);
    }
    cl::EnqueueArgs eargs(opencl_context.queue(),
                          vec_concat(internal::select_events<Args>(args)...),
                          global_thread_size);
    cl::KernelFunctor<internal::to_const_buffer_t<Args>&...> kernel_functor(
        kernel_);
    cl::Event kern_event
        = kernel_functor(eargs, internal::get_kernel_args(args)...);
    internal::assign_events<Args...>(kern_event, args...);
    return kern_event;
  }

  /** \ingroup kernel_executor_opencl
   * Executes a kernel
   * @tparam CallArgs The types of the callee arguments.
   * @tparam Args Parameter pack of all kernel argument types.
   * @param global_thread_size The global work size.
   * @param thread_block_size The thread block size.
   * @param args The arguments to pass to the kernel.
   * @return An Opencl event.
   */
  template <typename... CallArgs>
  auto operator()(cl::NDRange global_thread_size, cl::NDRange thread_block_size,
                  const CallArgs&... args) const {
    if (kernel_() == NULL) {
      kernel_ = compile_kernel(name_, sources_, opts_);
      opencl_context.register_kernel_cache(&kernel_);
    }
    cl::EnqueueArgs eargs(opencl_context.queue(),
                          vec_concat(internal::select_events<Args>(args)...),
                          global_thread_size, thread_block_size);
    cl::KernelFunctor<internal::to_const_buffer_t<Args>&...> kernel_functor(
        kernel_);
    cl::Event kern_event
        = kernel_functor(eargs, internal::get_kernel_args(args)...);
    internal::assign_events<Args...>(kern_event, args...);
    return kern_event;
  }

  /** \ingroup kernel_executor_opencl
   * Retrieves an option used for compiling the kernel.
   * @param option_name which option to retrieve
   * @return option value
   */
  int get_option(const std::string option_name) const {
    return opts_.at(option_name);
  }
};

}  // namespace opencl_kernels
}  // namespace math
}  // namespace stan

#endif
#endif
<|endoftext|>


<commit_before>#ifndef STAN_MATH_PRIM_FUN_INV_PHI_HPP
#define STAN_MATH_PRIM_FUN_INV_PHI_HPP

#include <stan/math/prim/fun/abs.hpp>
#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/err.hpp>
#include <stan/math/prim/fun/constants.hpp>
#include <stan/math/prim/fun/log1m.hpp>
#include <stan/math/prim/fun/Phi.hpp>
#include <stan/math/prim/fun/square.hpp>
#include <stan/math/prim/functor/apply_scalar_unary.hpp>
#include <cmath>

namespace stan {
namespace math {

/**
 * The inverse of the unit normal cumulative distribution function.
 *
 * The return value for a specified input probability, $p$, is
 * the unit normal variate, $x$, such that
 *
 * \f$\Phi(x) = \int_{-\infty}^x \mbox{\sf Norm}(x|0, 1) \ dx = p\f$
 *
 * Algorithm described in Wichura, M. J. (1988)
 * Algorithm AS 241: The percentage points of the normal distribution. Applied
 * Statistics, 37, 477–484. which provides precise results up to about 16
 * digits.
 *
 * @param p Argument between 0 and 1.
 * @return Real number
 */
inline double inv_Phi(double p) {
  check_bounded("inv_Phi", "Probability variable", p, 0, 1);

  if (p < 8e-311) {
    return NEGATIVE_INFTY;
  }
  if (p == 1) {
    return INFTY;
  }

  static const double a[8]
      = {3.3871328727963666080e+00, 1.3314166789178437745e+02,
         1.9715909503065514427e+03, 1.3731693765509461125e+04,
         4.5921953931549871457e+04, 6.7265770927008700853e+04,
         3.3430575583588128105e+04, 2.5090809287301226727e+03};
  static const double b[7]
      = {4.2313330701600911252e+01, 6.8718700749205790830e+02,
         5.3941960214247511077e+03, 2.1213794301586595867e+04,
         3.9307895800092710610e+04, 2.8729085735721942674e+04,
         5.2264952788528545610e+03};
  static const double c[8]
      = {1.42343711074968357734e+00, 4.63033784615654529590e+00,
         5.76949722146069140550e+00, 3.64784832476320460504e+00,
         1.27045825245236838258e+00, 2.41780725177450611770e-01,
         2.27238449892691845833e-02, 7.74545014278341407640e-04};
  static const double d[7]
      = {2.05319162663775882187e+00, 1.67638483018380384940e+00,
         6.89767334985100004550e-01, 1.48103976427480074590e-01,
         1.51986665636164571966e-02, 5.47593808499534494600e-04,
         1.05075007164441684324e-09};
  static const double e[8]
      = {6.65790464350110377720e+00, 5.46378491116411436990e+00,
         1.78482653991729133580e+00, 2.96560571828504891230e-01,
         2.65321895265761230930e-02, 1.24266094738807843860e-03,
         2.71155556874348757815e-05, 2.01033439929228813265e-07};
  static const double f[7]
      = {5.99832206555887937690e-01, 1.36929880922735805310e-01,
         1.48753612908506148525e-02, 7.86869131145613259100e-04,
         1.84631831751005468180e-05, 1.42151175831644588870e-07,
         2.04426310338993978564e-15};

  double q = p - 0.5;
  double r;
  double val;

  if (abs(q) <= .425) {
    r = .180625 - square(q);
    return q
           * (((((((a[7] * r + a[6]) * r + a[5]) * r + a[4]) * r + a[3]) * r
                + a[2])
                   * r
               + a[1])
                  * r
              + a[0])
           / (((((((b[6] * r + b[5]) * r + b[4]) * r + b[3]) * r + b[2]) * r
                + b[1])
                   * r
               + b[0])
                  * r
              + 1.0);
  } else {
    if (q < 0)
      r = p;
    else
      r = 1.0 - p;

    if (r <= 0)
      return 0;

    r = sqrt(-log(r));

    if (r <= 5.0) {
      r += -1.6;
      val = (((((((c[7] * r + c[6]) * r + c[5]) * r + c[4]) * r + c[3]) * r
               + c[2])
                  * r
              + c[1])
                 * r
             + c[0])
            / (((((((d[6] * r + d[5]) * r + d[4]) * r + d[3]) * r + d[2]) * r
                 + d[1])
                    * r
                + d[0])
                   * r
               + 1.0);
    } else {
      r -= 5.0;
      val = (((((((e[7] * r + e[6]) * r + e[5]) * r + e[4]) * r + e[3]) * r
               + e[2])
                  * r
              + e[1])
                 * r
             + e[0])
            / (((((((f[6] * r + f[5]) * r + f[4]) * r + f[3]) * r + f[2]) * r
                 + f[1])
                    * r
                + f[0])
                   * r
               + 1.0);
    }
    if (q < 0.0)
      return -val;
  }
}

/**
 * Structure to wrap inv_Phi() so it can be vectorized.
 *
 * @tparam T type of variable
 * @param x variable in range [0, 1]
 * @return Inverse unit normal CDF of x.
 * @throw std::domain_error if x is not between 0 and 1.
 */
struct inv_Phi_fun {
  template <typename T>
  static inline T fun(const T& x) {
    return inv_Phi(x);
  }
};

/**
 * Vectorized version of inv_Phi().
 *
 * @tparam T type of container
 * @param x variables in range [0, 1]
 * @return Inverse unit normal CDF of each value in x.
 * @throw std::domain_error if any value is not between 0 and 1.
 */
template <
    typename T,
    require_all_not_nonscalar_prim_or_rev_kernel_expression_t<T>* = nullptr,
    require_not_var_matrix_t<T>* = nullptr>
inline auto inv_Phi(const T& x) {
  return apply_scalar_unary<inv_Phi_fun, T>::apply(x);
}

}  // namespace math
}  // namespace stan

#endif
<commit_msg>needed final return for cpp<commit_after>#ifndef STAN_MATH_PRIM_FUN_INV_PHI_HPP
#define STAN_MATH_PRIM_FUN_INV_PHI_HPP

#include <stan/math/prim/fun/abs.hpp>
#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/err.hpp>
#include <stan/math/prim/fun/constants.hpp>
#include <stan/math/prim/fun/log1m.hpp>
#include <stan/math/prim/fun/Phi.hpp>
#include <stan/math/prim/fun/square.hpp>
#include <stan/math/prim/functor/apply_scalar_unary.hpp>
#include <cmath>

namespace stan {
namespace math {

/**
 * The inverse of the unit normal cumulative distribution function.
 *
 * The return value for a specified input probability, $p$, is
 * the unit normal variate, $x$, such that
 *
 * \f$\Phi(x) = \int_{-\infty}^x \mbox{\sf Norm}(x|0, 1) \ dx = p\f$
 *
 * Algorithm described in Wichura, M. J. (1988)
 * Algorithm AS 241: The percentage points of the normal distribution. Applied
 * Statistics, 37, 477–484. which provides precise results up to about 16
 * digits.
 *
 * @param p Argument between 0 and 1.
 * @return Real number
 */
inline double inv_Phi(double p) {
  check_bounded("inv_Phi", "Probability variable", p, 0, 1);

  if (p < 8e-311) {
    return NEGATIVE_INFTY;
  }
  if (p == 1) {
    return INFTY;
  }

  static const double a[8]
      = {3.3871328727963666080e+00, 1.3314166789178437745e+02,
         1.9715909503065514427e+03, 1.3731693765509461125e+04,
         4.5921953931549871457e+04, 6.7265770927008700853e+04,
         3.3430575583588128105e+04, 2.5090809287301226727e+03};
  static const double b[7]
      = {4.2313330701600911252e+01, 6.8718700749205790830e+02,
         5.3941960214247511077e+03, 2.1213794301586595867e+04,
         3.9307895800092710610e+04, 2.8729085735721942674e+04,
         5.2264952788528545610e+03};
  static const double c[8]
      = {1.42343711074968357734e+00, 4.63033784615654529590e+00,
         5.76949722146069140550e+00, 3.64784832476320460504e+00,
         1.27045825245236838258e+00, 2.41780725177450611770e-01,
         2.27238449892691845833e-02, 7.74545014278341407640e-04};
  static const double d[7]
      = {2.05319162663775882187e+00, 1.67638483018380384940e+00,
         6.89767334985100004550e-01, 1.48103976427480074590e-01,
         1.51986665636164571966e-02, 5.47593808499534494600e-04,
         1.05075007164441684324e-09};
  static const double e[8]
      = {6.65790464350110377720e+00, 5.46378491116411436990e+00,
         1.78482653991729133580e+00, 2.96560571828504891230e-01,
         2.65321895265761230930e-02, 1.24266094738807843860e-03,
         2.71155556874348757815e-05, 2.01033439929228813265e-07};
  static const double f[7]
      = {5.99832206555887937690e-01, 1.36929880922735805310e-01,
         1.48753612908506148525e-02, 7.86869131145613259100e-04,
         1.84631831751005468180e-05, 1.42151175831644588870e-07,
         2.04426310338993978564e-15};

  double q = p - 0.5;
  double r;
  double val;

  if (abs(q) <= .425) {
    r = .180625 - square(q);
    return q
           * (((((((a[7] * r + a[6]) * r + a[5]) * r + a[4]) * r + a[3]) * r
                + a[2])
                   * r
               + a[1])
                  * r
              + a[0])
           / (((((((b[6] * r + b[5]) * r + b[4]) * r + b[3]) * r + b[2]) * r
                + b[1])
                   * r
               + b[0])
                  * r
              + 1.0);
  } else {
    if (q < 0)
      r = p;
    else
      r = 1.0 - p;

    if (r <= 0)
      return 0;

    r = sqrt(-log(r));

    if (r <= 5.0) {
      r += -1.6;
      val = (((((((c[7] * r + c[6]) * r + c[5]) * r + c[4]) * r + c[3]) * r
               + c[2])
                  * r
              + c[1])
                 * r
             + c[0])
            / (((((((d[6] * r + d[5]) * r + d[4]) * r + d[3]) * r + d[2]) * r
                 + d[1])
                    * r
                + d[0])
                   * r
               + 1.0);
    } else {
      r -= 5.0;
      val = (((((((e[7] * r + e[6]) * r + e[5]) * r + e[4]) * r + e[3]) * r
               + e[2])
                  * r
              + e[1])
                 * r
             + e[0])
            / (((((((f[6] * r + f[5]) * r + f[4]) * r + f[3]) * r + f[2]) * r
                 + f[1])
                    * r
                + f[0])
                   * r
               + 1.0);
    }
    if (q < 0.0)
      return -val;
  }
  return val;
}

/**
 * Structure to wrap inv_Phi() so it can be vectorized.
 *
 * @tparam T type of variable
 * @param x variable in range [0, 1]
 * @return Inverse unit normal CDF of x.
 * @throw std::domain_error if x is not between 0 and 1.
 */
struct inv_Phi_fun {
  template <typename T>
  static inline T fun(const T& x) {
    return inv_Phi(x);
  }
};

/**
 * Vectorized version of inv_Phi().
 *
 * @tparam T type of container
 * @param x variables in range [0, 1]
 * @return Inverse unit normal CDF of each value in x.
 * @throw std::domain_error if any value is not between 0 and 1.
 */
template <
    typename T,
    require_all_not_nonscalar_prim_or_rev_kernel_expression_t<T>* = nullptr,
    require_not_var_matrix_t<T>* = nullptr>
inline auto inv_Phi(const T& x) {
  return apply_scalar_unary<inv_Phi_fun, T>::apply(x);
}

}  // namespace math
}  // namespace stan

#endif
<|endoftext|>


<commit_before>//Moose Includes
#include "Moose.h"
#include "UpdateAuxVars.h"
#include "KernelFactory.h"
#include "MaterialFactory.h"
#include "BoundaryCondition.h"
#include "BCFactory.h"
#include "ParallelUniqueId.h"

//libMesh includes
#include "numeric_vector.h"
#include "petsc_matrix.h"
#include "sparse_matrix.h"
#include "dof_map.h"
#include "mesh.h"
#include "boundary_info.h"
#include "elem_range.h"

#include <vector>

class ComputeInternalJacobians
{
public:
  ComputeInternalJacobians(const NumericVector<Number>& in_soln, SparseMatrix<Number>&  in_jacobian)
    :soln(in_soln),
     jacobian(in_jacobian)
  {}

  void operator() (const ConstElemRange & range) const
  {
    ParallelUniqueId puid;

    unsigned int tid = puid.id;

    DenseMatrix<Number> Ke;

    ConstElemRange::const_iterator el = range.begin();

    KernelIterator kernel_begin = KernelFactory::instance()->activeKernelsBegin(tid);
    KernelIterator kernel_end = KernelFactory::instance()->activeKernelsEnd(tid);
    KernelIterator kernel_it = kernel_begin;

    KernelIterator block_kernel_begin;
    KernelIterator block_kernel_end;
    KernelIterator block_kernel_it;

    unsigned int subdomain = 999999999;

    for (el = range.begin() ; el != range.end(); ++el)
    {
      const Elem* elem = *el;

      Kernel::reinit(tid, soln, elem, NULL, &Ke);

      unsigned int cur_subdomain = elem->subdomain_id();

      if(cur_subdomain != subdomain)
      {
        subdomain = cur_subdomain;

        Material * material = MaterialFactory::instance()->getMaterial(tid, subdomain);
        material->subdomainSetup();

        block_kernel_begin = KernelFactory::instance()->blockKernelsBegin(tid, subdomain);
        block_kernel_end = KernelFactory::instance()->blockKernelsEnd(tid, subdomain);

        //Global Kernels
        for(kernel_it=kernel_begin;kernel_it!=kernel_end;kernel_it++)
          (*kernel_it)->subdomainSetup();

        //Kernels on this block
        for(block_kernel_it=block_kernel_begin;block_kernel_it!=block_kernel_end;block_kernel_it++)
          (*block_kernel_it)->subdomainSetup();
      }

      //Global Kernels
      for(kernel_it=kernel_begin;kernel_it!=kernel_end;kernel_it++)
        (*kernel_it)->computeJacobian();

      //Kernels on this block
      for(block_kernel_it=block_kernel_begin;block_kernel_it!=block_kernel_end;block_kernel_it++)
        (*block_kernel_it)->computeJacobian();

      for (unsigned int side=0; side<elem->n_sides(); side++)
      {
        if (elem->neighbor(side) == NULL)
        {
          unsigned int boundary_id = Moose::mesh->boundary_info->boundary_id (elem, side);

          BCIterator bc_it = BCFactory::instance()->activeBCsBegin(tid,boundary_id);
          BCIterator bc_end = BCFactory::instance()->activeBCsEnd(tid,boundary_id);

          if(bc_it != bc_end)
          {
            BoundaryCondition::reinit(tid, soln, side, boundary_id);

            for(; bc_it!=bc_end; ++bc_it)
              (*bc_it)->computeJacobian();
          }
        }
      }

      Kernel::_dof_map->constrain_element_matrix (Ke, Kernel::_dof_indices[tid], false);

      {
        Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
        jacobian.add_matrix(Ke, Kernel::_dof_indices[tid]);
      }
    }

  }

protected:
  const NumericVector<Number>& soln;
  SparseMatrix<Number>& jacobian;
};

namespace Moose
{
  void compute_jacobian (const NumericVector<Number>& soln, SparseMatrix<Number>&  jacobian)
  {
    Moose::perf_log.push("compute_jacobian()","Solve");

#ifdef LIBMESH_HAVE_PETSC
    //Necessary for speed
    MatSetOption(static_cast<PetscMatrix<Number> &>(jacobian).mat(),MAT_KEEP_ZEROED_ROWS);
#endif

    update_aux_vars(soln);

    Threads::parallel_for(*Moose::getActiveLocalElementRange(),
                          ComputeInternalJacobians(soln, jacobian));

    jacobian.close();

    //Dirichlet BCs
    std::vector<int> zero_rows;

    std::vector<unsigned int> nodes;
    std::vector<short int> ids;

    mesh->boundary_info->build_node_list(nodes, ids);

    const unsigned int n_nodes = nodes.size();

    for(unsigned int i=0; i<n_nodes; i++)
    {
      unsigned int boundary_id = ids[i];

      BCIterator bc_it = BCFactory::instance()->activeNodalBCsBegin(0,boundary_id);
      BCIterator bc_end = BCFactory::instance()->activeNodalBCsEnd(0,boundary_id);

      if(bc_it != bc_end)
      {
          Node & node = mesh->node(nodes[i]);

          if(node.processor_id() == libMesh::processor_id())
          {
            for(; bc_it != bc_end; ++bc_it)
              //The first zero is for the system
              //The second zero only works with Lagrange elements!
              zero_rows.push_back(node.dof_number(0, (*bc_it)->variable(), 0));
          }
      }
    }

    //This zeroes the rows corresponding to Dirichlet BCs and puts a 1.0 on the diagonal
    jacobian.zero_rows(zero_rows, 1.0);

    jacobian.close();

    Moose::perf_log.pop("compute_jacobian()","Solve");
  }

class ComputeInternalJacobianBlocks
{
public:
  ComputeInternalJacobianBlocks(const NumericVector<Number>& in_soln, SparseMatrix<Number>&  in_jacobian, System& in_precond_system, unsigned int & in_ivar, unsigned int & in_jvar)
    :soln(in_soln),
     jacobian(in_jacobian),
     precond_system(in_precond_system),
     ivar(in_ivar),
     jvar(in_jvar)
  {}

  void operator() (const ConstElemRange & range) const
  {
    ParallelUniqueId puid;

    unsigned int tid = puid.id;

    ConstElemRange::const_iterator el = range.begin();

    KernelIterator kernel_begin = KernelFactory::instance()->activeKernelsBegin(tid);
    KernelIterator kernel_end = KernelFactory::instance()->activeKernelsEnd(tid);
    KernelIterator kernel_it = kernel_begin;

    KernelIterator block_kernel_begin;
    KernelIterator block_kernel_end;
    KernelIterator block_kernel_it;

    unsigned int subdomain = 999999999;

    DofMap & dof_map = precond_system.get_dof_map();
    DenseMatrix<Number> Ke;
    std::vector<unsigned int> dof_indices;

    jacobian.zero();

    for (el = range.begin() ; el != range.end(); ++el)
    {
      const Elem* elem = *el;

      Kernel::reinit(tid, soln, elem, NULL, NULL);

      dof_map.dof_indices(elem, dof_indices);

      Ke.resize(dof_indices.size(),dof_indices.size());

      unsigned int cur_subdomain = elem->subdomain_id();

      if(cur_subdomain != subdomain)
      {
        subdomain = cur_subdomain;

        Material * material = MaterialFactory::instance()->getMaterial(tid, subdomain);
        material->subdomainSetup();

        block_kernel_begin = KernelFactory::instance()->blockKernelsBegin(tid, subdomain);
        block_kernel_end = KernelFactory::instance()->blockKernelsEnd(tid, subdomain);

        //Global Kernels
        for(kernel_it=kernel_begin;kernel_it!=kernel_end;kernel_it++)
          (*kernel_it)->subdomainSetup();

        //Kernels on this block
        for(block_kernel_it=block_kernel_begin;block_kernel_it!=block_kernel_end;block_kernel_it++)
          (*block_kernel_it)->subdomainSetup();
      }

      //Global Kernels
      for(kernel_it=kernel_begin;kernel_it!=kernel_end;kernel_it++)
      {
        Kernel * kernel = *kernel_it;

        if(kernel->variable() == ivar)
          kernel->computeOffDiagJacobian(Ke,jvar);
      }

      //Kernels on this block
      for(block_kernel_it=block_kernel_begin;block_kernel_it!=block_kernel_end;block_kernel_it++)
      {
        Kernel * block_kernel = *block_kernel_it;

        if(block_kernel->variable() == ivar)
          block_kernel->computeOffDiagJacobian(Ke,jvar);
      }

      for (unsigned int side=0; side<elem->n_sides(); side++)
      {
        if (elem->neighbor(side) == NULL)
        {
          unsigned int boundary_id = mesh->boundary_info->boundary_id (elem, side);

          BCIterator bc_it = BCFactory::instance()->activeBCsBegin(tid,boundary_id);
          BCIterator bc_end = BCFactory::instance()->activeBCsEnd(tid,boundary_id);

          if(bc_it != bc_end)
          {
            BoundaryCondition::reinit(tid, soln, side, boundary_id);

            for(; bc_it!=bc_end; ++bc_it)
            {
              BoundaryCondition * bc = *bc_it;

              if(bc->variable() == ivar)
                bc->computeJacobianBlock(Ke,ivar,jvar);
            }
          }
        }
      }

      dof_map.constrain_element_matrix (Ke, dof_indices, false);

      {
        Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
        jacobian.add_matrix(Ke, dof_indices);
      }
    }
  }

protected:
  const NumericVector<Number>& soln;
  SparseMatrix<Number>& jacobian;
  System& precond_system;
  unsigned int & ivar;
  unsigned int & jvar;
};

  void compute_jacobian_block (const NumericVector<Number>& soln, SparseMatrix<Number>&  jacobian, System& precond_system, unsigned int ivar, unsigned int jvar)
  {
    Moose::perf_log.push("compute_jacobian_block()","Solve");

#ifdef LIBMESH_HAVE_PETSC
  //Necessary for speed
    MatSetOption(static_cast<PetscMatrix<Number> &>(jacobian).mat(),MAT_KEEP_ZEROED_ROWS);
#endif

    update_aux_vars(soln);
/*
    Threads::parallel_for(ConstElemRange(Moose::mesh->active_local_elements_begin(),
                                         Moose::mesh->active_local_elements_end(),1),
                          ComputeInternalJacobianBlocks(soln, jacobian, precond_system, ivar, jvar));
*/

  {
    unsigned int tid = 0;

    MeshBase::const_element_iterator el = Moose::mesh->active_local_elements_begin();
    const MeshBase::const_element_iterator end_el = Moose::mesh->active_local_elements_end();

    KernelIterator kernel_begin = KernelFactory::instance()->activeKernelsBegin(tid);
    KernelIterator kernel_end = KernelFactory::instance()->activeKernelsEnd(tid);
    KernelIterator kernel_it = kernel_begin;

    KernelIterator block_kernel_begin;
    KernelIterator block_kernel_end;
    KernelIterator block_kernel_it;

    unsigned int subdomain = 999999999;

    DofMap & dof_map = precond_system.get_dof_map();
    DenseMatrix<Number> Ke;
    std::vector<unsigned int> dof_indices;

    jacobian.zero();

    for (; el != end_el; ++el)
    {
      const Elem* elem = *el;

      Kernel::reinit(tid, soln, elem, NULL, NULL);

      dof_map.dof_indices(elem, dof_indices);

      Ke.resize(dof_indices.size(),dof_indices.size());

      unsigned int cur_subdomain = elem->subdomain_id();

      if(cur_subdomain != subdomain)
      {
        subdomain = cur_subdomain;

        Material * material = MaterialFactory::instance()->getMaterial(tid, subdomain);
        material->subdomainSetup();

        block_kernel_begin = KernelFactory::instance()->blockKernelsBegin(tid, subdomain);
        block_kernel_end = KernelFactory::instance()->blockKernelsEnd(tid, subdomain);

        //Global Kernels
        for(kernel_it=kernel_begin;kernel_it!=kernel_end;kernel_it++)
          (*kernel_it)->subdomainSetup();

        //Kernels on this block
        for(block_kernel_it=block_kernel_begin;block_kernel_it!=block_kernel_end;block_kernel_it++)
          (*block_kernel_it)->subdomainSetup();
      }

      //Global Kernels
      for(kernel_it=kernel_begin;kernel_it!=kernel_end;kernel_it++)
      {
        Kernel * kernel = *kernel_it;

        if(kernel->variable() == ivar)
          kernel->computeOffDiagJacobian(Ke,jvar);
      }

      //Kernels on this block
      for(block_kernel_it=block_kernel_begin;block_kernel_it!=block_kernel_end;block_kernel_it++)
      {
        Kernel * block_kernel = *block_kernel_it;

        if(block_kernel->variable() == ivar)
          block_kernel->computeOffDiagJacobian(Ke,jvar);
      }

      for (unsigned int side=0; side<elem->n_sides(); side++)
      {
        if (elem->neighbor(side) == NULL)
        {
          unsigned int boundary_id = mesh->boundary_info->boundary_id (elem, side);

          BCIterator bc_it = BCFactory::instance()->activeBCsBegin(tid,boundary_id);
          BCIterator bc_end = BCFactory::instance()->activeBCsEnd(tid,boundary_id);

          if(bc_it != bc_end)
          {
            BoundaryCondition::reinit(tid, soln, side, boundary_id);

            for(; bc_it!=bc_end; ++bc_it)
            {
              BoundaryCondition * bc = *bc_it;

              if(bc->variable() == ivar)
                bc->computeJacobianBlock(Ke,ivar,jvar);
            }
          }
        }
      }

      dof_map.constrain_element_matrix (Ke, dof_indices, false);

      jacobian.add_matrix(Ke, dof_indices);
    }
  }

    jacobian.close();

    //Dirichlet BCs
    std::vector<int> zero_rows;

    std::vector<unsigned int> nodes;
    std::vector<short int> ids;

    mesh->boundary_info->build_node_list(nodes, ids);

    const unsigned int n_nodes = nodes.size();

    for(unsigned int i=0; i<n_nodes; i++)
    {
      unsigned int boundary_id = ids[i];

      BCIterator bc_it = BCFactory::instance()->activeNodalBCsBegin(0,boundary_id);
      BCIterator bc_end = BCFactory::instance()->activeNodalBCsEnd(0,boundary_id);

      if(bc_it != bc_end)
      {
        Node & node = mesh->node(nodes[i]);

        if(node.processor_id() == libMesh::processor_id())
        {
          for(; bc_it != bc_end; ++bc_it)
            //The first zero is for the variable number... there is only one variable in each mini-system
            //The second zero only works with Lagrange elements!
            if((*bc_it)->variable() == ivar)
              zero_rows.push_back(node.dof_number(precond_system.number(), 0, 0));
        }
      }
    }

    jacobian.close();

    //This zeroes the rows corresponding to Dirichlet BCs and puts a 1.0 on the diagonal
    jacobian.zero_rows(zero_rows, 1.0);

    jacobian.close();

    Moose::perf_log.pop("compute_jacobian_block()","Solve");
  }

}
<commit_msg>Petsc 3.0.0 compatibility.<commit_after>//Moose Includes
#include "Moose.h"
#include "UpdateAuxVars.h"
#include "KernelFactory.h"
#include "MaterialFactory.h"
#include "BoundaryCondition.h"
#include "BCFactory.h"
#include "ParallelUniqueId.h"

//libMesh includes
#include "numeric_vector.h"
#include "petsc_matrix.h"
#include "sparse_matrix.h"
#include "dof_map.h"
#include "mesh.h"
#include "boundary_info.h"
#include "elem_range.h"

#include <vector>

class ComputeInternalJacobians
{
public:
  ComputeInternalJacobians(const NumericVector<Number>& in_soln, SparseMatrix<Number>&  in_jacobian)
    :soln(in_soln),
     jacobian(in_jacobian)
  {}

  void operator() (const ConstElemRange & range) const
  {
    ParallelUniqueId puid;

    unsigned int tid = puid.id;

    DenseMatrix<Number> Ke;

    ConstElemRange::const_iterator el = range.begin();

    KernelIterator kernel_begin = KernelFactory::instance()->activeKernelsBegin(tid);
    KernelIterator kernel_end = KernelFactory::instance()->activeKernelsEnd(tid);
    KernelIterator kernel_it = kernel_begin;

    KernelIterator block_kernel_begin;
    KernelIterator block_kernel_end;
    KernelIterator block_kernel_it;

    unsigned int subdomain = 999999999;

    for (el = range.begin() ; el != range.end(); ++el)
    {
      const Elem* elem = *el;

      Kernel::reinit(tid, soln, elem, NULL, &Ke);

      unsigned int cur_subdomain = elem->subdomain_id();

      if(cur_subdomain != subdomain)
      {
        subdomain = cur_subdomain;

        Material * material = MaterialFactory::instance()->getMaterial(tid, subdomain);
        material->subdomainSetup();

        block_kernel_begin = KernelFactory::instance()->blockKernelsBegin(tid, subdomain);
        block_kernel_end = KernelFactory::instance()->blockKernelsEnd(tid, subdomain);

        //Global Kernels
        for(kernel_it=kernel_begin;kernel_it!=kernel_end;kernel_it++)
          (*kernel_it)->subdomainSetup();

        //Kernels on this block
        for(block_kernel_it=block_kernel_begin;block_kernel_it!=block_kernel_end;block_kernel_it++)
          (*block_kernel_it)->subdomainSetup();
      }

      //Global Kernels
      for(kernel_it=kernel_begin;kernel_it!=kernel_end;kernel_it++)
        (*kernel_it)->computeJacobian();

      //Kernels on this block
      for(block_kernel_it=block_kernel_begin;block_kernel_it!=block_kernel_end;block_kernel_it++)
        (*block_kernel_it)->computeJacobian();

      for (unsigned int side=0; side<elem->n_sides(); side++)
      {
        if (elem->neighbor(side) == NULL)
        {
          unsigned int boundary_id = Moose::mesh->boundary_info->boundary_id (elem, side);

          BCIterator bc_it = BCFactory::instance()->activeBCsBegin(tid,boundary_id);
          BCIterator bc_end = BCFactory::instance()->activeBCsEnd(tid,boundary_id);

          if(bc_it != bc_end)
          {
            BoundaryCondition::reinit(tid, soln, side, boundary_id);

            for(; bc_it!=bc_end; ++bc_it)
              (*bc_it)->computeJacobian();
          }
        }
      }

      Kernel::_dof_map->constrain_element_matrix (Ke, Kernel::_dof_indices[tid], false);

      {
        Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
        jacobian.add_matrix(Ke, Kernel::_dof_indices[tid]);
      }
    }

  }

protected:
  const NumericVector<Number>& soln;
  SparseMatrix<Number>& jacobian;
};

namespace Moose
{
  void compute_jacobian (const NumericVector<Number>& soln, SparseMatrix<Number>&  jacobian)
  {
    Moose::perf_log.push("compute_jacobian()","Solve");

#ifdef LIBMESH_HAVE_PETSC
    //Necessary for speed
#if PETSC_VERSION_LESS_THAN(3,0,0)
    MatSetOption(static_cast<PetscMatrix<Number> &>(jacobian).mat(),MAT_KEEP_ZEROED_ROWS);
#else
    // In Petsc 3.0.0, MatSetOption has three args...the third arg
    // determines whether the option is set (true) or unset (false)
    MatSetOption(static_cast<PetscMatrix<Number> &>(jacobian).mat(),
		 MAT_KEEP_ZEROED_ROWS,
		 PETSC_TRUE);
#endif

#endif

    update_aux_vars(soln);

    Threads::parallel_for(*Moose::getActiveLocalElementRange(),
                          ComputeInternalJacobians(soln, jacobian));

    jacobian.close();

    //Dirichlet BCs
    std::vector<int> zero_rows;

    std::vector<unsigned int> nodes;
    std::vector<short int> ids;

    mesh->boundary_info->build_node_list(nodes, ids);

    const unsigned int n_nodes = nodes.size();

    for(unsigned int i=0; i<n_nodes; i++)
    {
      unsigned int boundary_id = ids[i];

      BCIterator bc_it = BCFactory::instance()->activeNodalBCsBegin(0,boundary_id);
      BCIterator bc_end = BCFactory::instance()->activeNodalBCsEnd(0,boundary_id);

      if(bc_it != bc_end)
      {
          Node & node = mesh->node(nodes[i]);

          if(node.processor_id() == libMesh::processor_id())
          {
            for(; bc_it != bc_end; ++bc_it)
              //The first zero is for the system
              //The second zero only works with Lagrange elements!
              zero_rows.push_back(node.dof_number(0, (*bc_it)->variable(), 0));
          }
      }
    }

    //This zeroes the rows corresponding to Dirichlet BCs and puts a 1.0 on the diagonal
    jacobian.zero_rows(zero_rows, 1.0);

    jacobian.close();

    Moose::perf_log.pop("compute_jacobian()","Solve");
  }

class ComputeInternalJacobianBlocks
{
public:
  ComputeInternalJacobianBlocks(const NumericVector<Number>& in_soln, SparseMatrix<Number>&  in_jacobian, System& in_precond_system, unsigned int & in_ivar, unsigned int & in_jvar)
    :soln(in_soln),
     jacobian(in_jacobian),
     precond_system(in_precond_system),
     ivar(in_ivar),
     jvar(in_jvar)
  {}

  void operator() (const ConstElemRange & range) const
  {
    ParallelUniqueId puid;

    unsigned int tid = puid.id;

    ConstElemRange::const_iterator el = range.begin();

    KernelIterator kernel_begin = KernelFactory::instance()->activeKernelsBegin(tid);
    KernelIterator kernel_end = KernelFactory::instance()->activeKernelsEnd(tid);
    KernelIterator kernel_it = kernel_begin;

    KernelIterator block_kernel_begin;
    KernelIterator block_kernel_end;
    KernelIterator block_kernel_it;

    unsigned int subdomain = 999999999;

    DofMap & dof_map = precond_system.get_dof_map();
    DenseMatrix<Number> Ke;
    std::vector<unsigned int> dof_indices;

    jacobian.zero();

    for (el = range.begin() ; el != range.end(); ++el)
    {
      const Elem* elem = *el;

      Kernel::reinit(tid, soln, elem, NULL, NULL);

      dof_map.dof_indices(elem, dof_indices);

      Ke.resize(dof_indices.size(),dof_indices.size());

      unsigned int cur_subdomain = elem->subdomain_id();

      if(cur_subdomain != subdomain)
      {
        subdomain = cur_subdomain;

        Material * material = MaterialFactory::instance()->getMaterial(tid, subdomain);
        material->subdomainSetup();

        block_kernel_begin = KernelFactory::instance()->blockKernelsBegin(tid, subdomain);
        block_kernel_end = KernelFactory::instance()->blockKernelsEnd(tid, subdomain);

        //Global Kernels
        for(kernel_it=kernel_begin;kernel_it!=kernel_end;kernel_it++)
          (*kernel_it)->subdomainSetup();

        //Kernels on this block
        for(block_kernel_it=block_kernel_begin;block_kernel_it!=block_kernel_end;block_kernel_it++)
          (*block_kernel_it)->subdomainSetup();
      }

      //Global Kernels
      for(kernel_it=kernel_begin;kernel_it!=kernel_end;kernel_it++)
      {
        Kernel * kernel = *kernel_it;

        if(kernel->variable() == ivar)
          kernel->computeOffDiagJacobian(Ke,jvar);
      }

      //Kernels on this block
      for(block_kernel_it=block_kernel_begin;block_kernel_it!=block_kernel_end;block_kernel_it++)
      {
        Kernel * block_kernel = *block_kernel_it;

        if(block_kernel->variable() == ivar)
          block_kernel->computeOffDiagJacobian(Ke,jvar);
      }

      for (unsigned int side=0; side<elem->n_sides(); side++)
      {
        if (elem->neighbor(side) == NULL)
        {
          unsigned int boundary_id = mesh->boundary_info->boundary_id (elem, side);

          BCIterator bc_it = BCFactory::instance()->activeBCsBegin(tid,boundary_id);
          BCIterator bc_end = BCFactory::instance()->activeBCsEnd(tid,boundary_id);

          if(bc_it != bc_end)
          {
            BoundaryCondition::reinit(tid, soln, side, boundary_id);

            for(; bc_it!=bc_end; ++bc_it)
            {
              BoundaryCondition * bc = *bc_it;

              if(bc->variable() == ivar)
                bc->computeJacobianBlock(Ke,ivar,jvar);
            }
          }
        }
      }

      dof_map.constrain_element_matrix (Ke, dof_indices, false);

      {
        Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
        jacobian.add_matrix(Ke, dof_indices);
      }
    }
  }

protected:
  const NumericVector<Number>& soln;
  SparseMatrix<Number>& jacobian;
  System& precond_system;
  unsigned int & ivar;
  unsigned int & jvar;
};

  void compute_jacobian_block (const NumericVector<Number>& soln, SparseMatrix<Number>&  jacobian, System& precond_system, unsigned int ivar, unsigned int jvar)
  {
    Moose::perf_log.push("compute_jacobian_block()","Solve");

#ifdef LIBMESH_HAVE_PETSC
  //Necessary for speed
#if PETSC_VERSION_LESS_THAN(3,0,0)
    MatSetOption(static_cast<PetscMatrix<Number> &>(jacobian).mat(),MAT_KEEP_ZEROED_ROWS);
#else
    // In Petsc 3.0.0, MatSetOption has three args...the third arg
    // determines whether the option is set (true) or unset (false)
    MatSetOption(static_cast<PetscMatrix<Number> &>(jacobian).mat(),
		 MAT_KEEP_ZEROED_ROWS,
		 PETSC_TRUE);
#endif
#endif

    update_aux_vars(soln);
/*
    Threads::parallel_for(ConstElemRange(Moose::mesh->active_local_elements_begin(),
                                         Moose::mesh->active_local_elements_end(),1),
                          ComputeInternalJacobianBlocks(soln, jacobian, precond_system, ivar, jvar));
*/

  {
    unsigned int tid = 0;

    MeshBase::const_element_iterator el = Moose::mesh->active_local_elements_begin();
    const MeshBase::const_element_iterator end_el = Moose::mesh->active_local_elements_end();

    KernelIterator kernel_begin = KernelFactory::instance()->activeKernelsBegin(tid);
    KernelIterator kernel_end = KernelFactory::instance()->activeKernelsEnd(tid);
    KernelIterator kernel_it = kernel_begin;

    KernelIterator block_kernel_begin;
    KernelIterator block_kernel_end;
    KernelIterator block_kernel_it;

    unsigned int subdomain = 999999999;

    DofMap & dof_map = precond_system.get_dof_map();
    DenseMatrix<Number> Ke;
    std::vector<unsigned int> dof_indices;

    jacobian.zero();

    for (; el != end_el; ++el)
    {
      const Elem* elem = *el;

      Kernel::reinit(tid, soln, elem, NULL, NULL);

      dof_map.dof_indices(elem, dof_indices);

      Ke.resize(dof_indices.size(),dof_indices.size());

      unsigned int cur_subdomain = elem->subdomain_id();

      if(cur_subdomain != subdomain)
      {
        subdomain = cur_subdomain;

        Material * material = MaterialFactory::instance()->getMaterial(tid, subdomain);
        material->subdomainSetup();

        block_kernel_begin = KernelFactory::instance()->blockKernelsBegin(tid, subdomain);
        block_kernel_end = KernelFactory::instance()->blockKernelsEnd(tid, subdomain);

        //Global Kernels
        for(kernel_it=kernel_begin;kernel_it!=kernel_end;kernel_it++)
          (*kernel_it)->subdomainSetup();

        //Kernels on this block
        for(block_kernel_it=block_kernel_begin;block_kernel_it!=block_kernel_end;block_kernel_it++)
          (*block_kernel_it)->subdomainSetup();
      }

      //Global Kernels
      for(kernel_it=kernel_begin;kernel_it!=kernel_end;kernel_it++)
      {
        Kernel * kernel = *kernel_it;

        if(kernel->variable() == ivar)
          kernel->computeOffDiagJacobian(Ke,jvar);
      }

      //Kernels on this block
      for(block_kernel_it=block_kernel_begin;block_kernel_it!=block_kernel_end;block_kernel_it++)
      {
        Kernel * block_kernel = *block_kernel_it;

        if(block_kernel->variable() == ivar)
          block_kernel->computeOffDiagJacobian(Ke,jvar);
      }

      for (unsigned int side=0; side<elem->n_sides(); side++)
      {
        if (elem->neighbor(side) == NULL)
        {
          unsigned int boundary_id = mesh->boundary_info->boundary_id (elem, side);

          BCIterator bc_it = BCFactory::instance()->activeBCsBegin(tid,boundary_id);
          BCIterator bc_end = BCFactory::instance()->activeBCsEnd(tid,boundary_id);

          if(bc_it != bc_end)
          {
            BoundaryCondition::reinit(tid, soln, side, boundary_id);

            for(; bc_it!=bc_end; ++bc_it)
            {
              BoundaryCondition * bc = *bc_it;

              if(bc->variable() == ivar)
                bc->computeJacobianBlock(Ke,ivar,jvar);
            }
          }
        }
      }

      dof_map.constrain_element_matrix (Ke, dof_indices, false);

      jacobian.add_matrix(Ke, dof_indices);
    }
  }

    jacobian.close();

    //Dirichlet BCs
    std::vector<int> zero_rows;

    std::vector<unsigned int> nodes;
    std::vector<short int> ids;

    mesh->boundary_info->build_node_list(nodes, ids);

    const unsigned int n_nodes = nodes.size();

    for(unsigned int i=0; i<n_nodes; i++)
    {
      unsigned int boundary_id = ids[i];

      BCIterator bc_it = BCFactory::instance()->activeNodalBCsBegin(0,boundary_id);
      BCIterator bc_end = BCFactory::instance()->activeNodalBCsEnd(0,boundary_id);

      if(bc_it != bc_end)
      {
        Node & node = mesh->node(nodes[i]);

        if(node.processor_id() == libMesh::processor_id())
        {
          for(; bc_it != bc_end; ++bc_it)
            //The first zero is for the variable number... there is only one variable in each mini-system
            //The second zero only works with Lagrange elements!
            if((*bc_it)->variable() == ivar)
              zero_rows.push_back(node.dof_number(precond_system.number(), 0, 0));
        }
      }
    }

    jacobian.close();

    //This zeroes the rows corresponding to Dirichlet BCs and puts a 1.0 on the diagonal
    jacobian.zero_rows(zero_rows, 1.0);

    jacobian.close();

    Moose::perf_log.pop("compute_jacobian_block()","Solve");
  }

}
<|endoftext|>


<commit_before>/*
 * Copyright (c) [2004-2014] Novell, Inc.
 * Copyright (c) [2016-2017] SUSE LLC
 *
 * All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License as published
 * by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, contact Novell, Inc.
 *
 * To contact Novell about this file by physical or electronic mail, you may
 * find current contact information at www.novell.com.
 */

#include <algorithm>

#include "storage/Utils/AppUtil.h"
#include "storage/Utils/SystemCmd.h"
#include "storage/Utils/StorageDefines.h"
#include "storage/SystemInfo/SystemInfo.h"
#include "storage/SystemInfo/CmdBlkid.h"
#include "storage/Filesystems/FilesystemImpl.h"

namespace storage
{
    using namespace std;

    Blkid::Blkid()
    {
	SystemCmd cmd(BLKIDBIN " -c '/dev/null'");
	if (cmd.retcode() == 0)
	    parse(cmd.stdout());
    }

    Blkid::Blkid(const string& device)
    {
	SystemCmd cmd(BLKIDBIN " -c '/dev/null' " + quote(device));
	if (cmd.retcode() == 0)
	    parse(cmd.stdout());
    }

    void
    Blkid::parse(const vector<string>& lines)
    {
	static const map<string, FsType> fs_table = {
	    { "btrfs", FsType::BTRFS },
	    { "ext2", FsType::EXT2 },
	    { "ext3", FsType::EXT3 },
	    { "ext4", FsType::EXT4 },
	    { "hfs", FsType::HFS },
	    { "hfsplus", FsType::HFSPLUS },
	    { "jfs", FsType::JFS },
	    { "msdos", FsType::VFAT },
	    { "nilfs2", FsType::NILFS2 },
	    { "ntfs", FsType::NTFS },
	    { "reiserfs", FsType::REISERFS },
	    { "swap", FsType::SWAP },
	    { "vfat", FsType::VFAT },
	    { "xfs", FsType::XFS },
	    { "iso9660", FsType::ISO9660 },
	    { "udf", FsType::UDF }
	};

	data.clear();

	for (vector<string>::const_iterator it = lines.begin(); it != lines.end(); ++it)
	{
	    string::size_type pos = it->find(":");
	    if (pos == string::npos)
		continue;

	    string device = string(*it, 0, pos);
	    list<string> l = splitString(string(*it, pos + 1), " \t\n", true, true, "\"");

	    Entry entry;

	    const map<string, string> m = makeMap(l, "=", "\"");

	    map<string, string>::const_iterator i = m.find("TYPE");
	    if (i != m.end())
	    {
		map<string, FsType>::const_iterator it2 = fs_table.find(i->second);
		if (it2 != fs_table.end())
		{
		    entry.is_fs = true;
		    entry.fs_type = it2->second;
		}
		else if (i->second == "linux_raid_member")
		{
		    entry.is_md = true;
		}
		else if (i->second == "LVM2_member")
		{
		    entry.is_lvm = true;
		}
		else if (i->second == "crypto_LUKS")
		{
		    entry.is_luks = true;
		}
		else if (i->second == "bcache")
		{
		    entry.is_bcache = true;
		}
	    }

	    if (entry.is_fs)
	    {
		i = m.find("UUID");
		if (i != m.end())
		    entry.fs_uuid = i->second;

		i = m.find("LABEL");
		if (i != m.end())
		    entry.fs_label = i->second;
	    }

	    if (entry.is_luks)
	    {
		i = m.find("UUID");
		if (i != m.end())
		    entry.luks_uuid = i->second;
	    }

	    if (entry.is_bcache)
	    {
		i = m.find("UUID");
		if (i != m.end())
		    entry.bcache_uuid = i->second;
	    }

	    if (entry.is_fs || entry.is_md || entry.is_lvm || entry.is_luks || entry.is_bcache)
		data[device] = entry;
	}

	y2mil(*this);
    }

    bool
    Blkid::find_by_name(const string& device, Entry& entry, SystemInfo& systeminfo) const
    {
	const_iterator it = data.find(device);
	if (it != data.end())
	{
	    entry = it->second;
	    return true;
	}

	dev_t majorminor = systeminfo.getCmdUdevadmInfo(device).get_majorminor();

	for (const value_type& value : data)
	{
	    if (systeminfo.getCmdUdevadmInfo(value.first).get_majorminor() == majorminor)
	    {
		entry = value.second;
		return true;
	    }
	}

	return false;
    }

    bool
    Blkid::get_sole_entry(Entry& entry) const
    {
	if (data.size() == 1)
	{
	    entry = data.begin()->second;
	    return true;
	}

	return false;
    }

    bool
    Blkid::any_md() const
    {
	return std::any_of(data.begin(), data.end(), [](const value_type& value) { return value.second.is_md; });
    }

    bool
    Blkid::any_lvm() const
    {
	return std::any_of(data.begin(), data.end(), [](const value_type& value) { return value.second.is_lvm; });
    }

    bool
    Blkid::any_luks() const
    {
	return std::any_of(data.begin(), data.end(), [](const value_type& value) { return value.second.is_luks; });
    }

    bool
    Blkid::any_bcache() const
    {
	return std::any_of(data.begin(), data.end(), [](const value_type& value) { return value.second.is_bcache; });
    }

    std::ostream&
    operator<<(std::ostream& s, const Blkid& blkid)
    {
	for (Blkid::const_iterator it = blkid.data.begin(); it != blkid.data.end(); ++it)
	    s << "data[" << it->first << "] -> " << it->second << '\n';

	return s;
    }

    std::ostream&
    operator<<(std::ostream& s, const Blkid::Entry& entry)
    {
	if (entry.is_fs)
	{
	    s << "is-fs:" << entry.is_fs;
	    s << " fs-type:" << toString(entry.fs_type);
	    if (!entry.fs_uuid.empty())
		s << " fs-uuid:" << entry.fs_uuid;
	    if (!entry.fs_label.empty())
		s << " fs-label:" << entry.fs_label;
	}

	if (entry.is_md)
	{
	    s << "is-md:" << entry.is_md;
	}

	if (entry.is_lvm)
	{
	    s << "is-lvm:" << entry.is_lvm;
	}

	if (entry.is_luks)
	{
	    s << "is-luks:" << entry.is_luks;
	    if (!entry.luks_uuid.empty())
		s << " luks-uuid:" << entry.luks_uuid;
	}

	if (entry.is_bcache)
	{
	    s << "is-bcache:" << entry.is_bcache;
	    if (!entry.bcache_uuid.empty())
		s << " bcache-uuid:" << entry.bcache_uuid;
	}

	return s;
    }

}
<commit_msg>- renamed variable<commit_after>/*
 * Copyright (c) [2004-2014] Novell, Inc.
 * Copyright (c) [2016-2017] SUSE LLC
 *
 * All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License as published
 * by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, contact Novell, Inc.
 *
 * To contact Novell about this file by physical or electronic mail, you may
 * find current contact information at www.novell.com.
 */

#include <algorithm>

#include "storage/Utils/AppUtil.h"
#include "storage/Utils/SystemCmd.h"
#include "storage/Utils/StorageDefines.h"
#include "storage/SystemInfo/SystemInfo.h"
#include "storage/SystemInfo/CmdBlkid.h"
#include "storage/Filesystems/FilesystemImpl.h"

namespace storage
{
    using namespace std;

    Blkid::Blkid()
    {
	SystemCmd cmd(BLKIDBIN " -c '/dev/null'");
	if (cmd.retcode() == 0)
	    parse(cmd.stdout());
    }

    Blkid::Blkid(const string& device)
    {
	SystemCmd cmd(BLKIDBIN " -c '/dev/null' " + quote(device));
	if (cmd.retcode() == 0)
	    parse(cmd.stdout());
    }

    void
    Blkid::parse(const vector<string>& lines)
    {
	static const map<string, FsType> fs_table = {
	    { "btrfs", FsType::BTRFS },
	    { "ext2", FsType::EXT2 },
	    { "ext3", FsType::EXT3 },
	    { "ext4", FsType::EXT4 },
	    { "hfs", FsType::HFS },
	    { "hfsplus", FsType::HFSPLUS },
	    { "jfs", FsType::JFS },
	    { "msdos", FsType::VFAT },
	    { "nilfs2", FsType::NILFS2 },
	    { "ntfs", FsType::NTFS },
	    { "reiserfs", FsType::REISERFS },
	    { "swap", FsType::SWAP },
	    { "vfat", FsType::VFAT },
	    { "xfs", FsType::XFS },
	    { "iso9660", FsType::ISO9660 },
	    { "udf", FsType::UDF }
	};

	data.clear();

	for (vector<string>::const_iterator it = lines.begin(); it != lines.end(); ++it)
	{
	    string::size_type pos = it->find(":");
	    if (pos == string::npos)
		continue;

	    string device = string(*it, 0, pos);
	    list<string> l = splitString(string(*it, pos + 1), " \t\n", true, true, "\"");

	    Entry entry;

	    const map<string, string> m = makeMap(l, "=", "\"");

	    map<string, string>::const_iterator it1 = m.find("TYPE");
	    if (it1 != m.end())
	    {
		map<string, FsType>::const_iterator it2 = fs_table.find(it1->second);
		if (it2 != fs_table.end())
		{
		    entry.is_fs = true;
		    entry.fs_type = it2->second;
		}
		else if (it1->second == "linux_raid_member")
		{
		    entry.is_md = true;
		}
		else if (it1->second == "LVM2_member")
		{
		    entry.is_lvm = true;
		}
		else if (it1->second == "crypto_LUKS")
		{
		    entry.is_luks = true;
		}
		else if (it1->second == "bcache")
		{
		    entry.is_bcache = true;
		}
	    }

	    if (entry.is_fs)
	    {
		it1 = m.find("UUID");
		if (it1 != m.end())
		    entry.fs_uuid = it1->second;

		it1 = m.find("LABEL");
		if (it1 != m.end())
		    entry.fs_label = it1->second;
	    }

	    if (entry.is_luks)
	    {
		it1 = m.find("UUID");
		if (it1 != m.end())
		    entry.luks_uuid = it1->second;
	    }

	    if (entry.is_bcache)
	    {
		it1 = m.find("UUID");
		if (it1 != m.end())
		    entry.bcache_uuid = it1->second;
	    }

	    if (entry.is_fs || entry.is_md || entry.is_lvm || entry.is_luks || entry.is_bcache)
		data[device] = entry;
	}

	y2mil(*this);
    }

    bool
    Blkid::find_by_name(const string& device, Entry& entry, SystemInfo& systeminfo) const
    {
	const_iterator it = data.find(device);
	if (it != data.end())
	{
	    entry = it->second;
	    return true;
	}

	dev_t majorminor = systeminfo.getCmdUdevadmInfo(device).get_majorminor();

	for (const value_type& value : data)
	{
	    if (systeminfo.getCmdUdevadmInfo(value.first).get_majorminor() == majorminor)
	    {
		entry = value.second;
		return true;
	    }
	}

	return false;
    }

    bool
    Blkid::get_sole_entry(Entry& entry) const
    {
	if (data.size() == 1)
	{
	    entry = data.begin()->second;
	    return true;
	}

	return false;
    }

    bool
    Blkid::any_md() const
    {
	return std::any_of(data.begin(), data.end(), [](const value_type& value) { return value.second.is_md; });
    }

    bool
    Blkid::any_lvm() const
    {
	return std::any_of(data.begin(), data.end(), [](const value_type& value) { return value.second.is_lvm; });
    }

    bool
    Blkid::any_luks() const
    {
	return std::any_of(data.begin(), data.end(), [](const value_type& value) { return value.second.is_luks; });
    }

    bool
    Blkid::any_bcache() const
    {
	return std::any_of(data.begin(), data.end(), [](const value_type& value) { return value.second.is_bcache; });
    }

    std::ostream&
    operator<<(std::ostream& s, const Blkid& blkid)
    {
	for (Blkid::const_iterator it = blkid.data.begin(); it != blkid.data.end(); ++it)
	    s << "data[" << it->first << "] -> " << it->second << '\n';

	return s;
    }

    std::ostream&
    operator<<(std::ostream& s, const Blkid::Entry& entry)
    {
	if (entry.is_fs)
	{
	    s << "is-fs:" << entry.is_fs;
	    s << " fs-type:" << toString(entry.fs_type);
	    if (!entry.fs_uuid.empty())
		s << " fs-uuid:" << entry.fs_uuid;
	    if (!entry.fs_label.empty())
		s << " fs-label:" << entry.fs_label;
	}

	if (entry.is_md)
	{
	    s << "is-md:" << entry.is_md;
	}

	if (entry.is_lvm)
	{
	    s << "is-lvm:" << entry.is_lvm;
	}

	if (entry.is_luks)
	{
	    s << "is-luks:" << entry.is_luks;
	    if (!entry.luks_uuid.empty())
		s << " luks-uuid:" << entry.luks_uuid;
	}

	if (entry.is_bcache)
	{
	    s << "is-bcache:" << entry.is_bcache;
	    if (!entry.bcache_uuid.empty())
		s << " bcache-uuid:" << entry.bcache_uuid;
	}

	return s;
    }

}
<|endoftext|>


<commit_before><commit_msg>INTEGRATION: CWS ooo64bit01 (1.7.414); FILE MERGED 2004/03/15 23:18:30 fa 1.7.414.1: First bits of 64-bitness.  #i25651# & more<commit_after><|endoftext|>


<commit_before>#pragma once

namespace frea {
	#define countof(a) (sizeof(a)/sizeof(a[0]))
	#define DEF_OP(func, op) \
		template <class R> \
		static auto func(const R& t0, const R& t1) { \
			R ret; \
			for(int i=0 ; i<int(countof(t0.m)) ; i++) \
				ret.m[i] = t0.m[i] op t1.m[i]; \
			return ret; \
		}
	template <class T, bool F>
	struct _info {
		static T OneV() { return ~0; }
		DEF_OP(And, &)
		DEF_OP(Or, |)
		DEF_OP(Xor, ^)
	};
	template <class T>
	struct _info<T, true> {
		static int32_t ToInt(float);
		static int64_t ToInt(double);
		template <class T2>
		using ToInt_t = decltype(ToInt(T2()));

		using i_type = _info<T,true>::ToInt_t<T>;
		using f_type = T;
		static f_type OneV() {
			const i_type tmp(~0);
			return *(f_type*)&tmp;
		}
		#define DEF_OPF(func, op) \
			template <class R> \
			static auto func(const R& t0, const R& t1) { \
				R ret; \
				for(int i=0 ; i<int(countof(t0.m)) ; i++) { \
					const i_type tmp = *reinterpret_cast<const i_type*>(&t0.m[i]) op \
										*reinterpret_cast<const i_type*>(&t1.m[i]); \
					ret.m[i] = *reinterpret_cast<const f_type*>(&tmp); \
				} \
				return ret; \
			}
		DEF_OPF(And, &)
		DEF_OPF(Or, |)
		DEF_OPF(Xor, ^)
		#undef DEF_OPF
	};
	template <class T, int N, bool A>
	struct info<Data<T,N,A>> : _info<T, std::is_floating_point<T>{}> {
		constexpr static int capacity = N;
		using base_t = _info<T, std::is_floating_point<T>{}>;
		using reg_t = Data<T,N,A>;
		using value_t = T;

		DEF_OP(Add, +)
		DEF_OP(Sub, -)
		DEF_OP(Mul, *)
		DEF_OP(Div, /)

		static auto Zero() { return reg_t(0); }
		static auto One() { return reg_t(base_t::OneV()); }
		static auto LoadU(const value_t* v) { return reg_t(v); }
		static auto Load(const value_t* v) { return reg_t(v); }
		static auto Set1(const value_t& v) { return reg_t(v); }
		template <class... Ts>
		static auto Set(const Ts&... ts) { return reg_t(ts...); }
		template <int Pos>
		static auto MaskH(IConst<Pos>) { return reg_t(reg_t::TagMask, IConst<Pos>(), base_t::OneV()); }
		template <int Pos>
		static auto PickAt(IConst<Pos>) { return reg_t(reg_t::TagSet, IConst<Pos>(), base_t::OneV()); }
		template <int Pos>
		static value_t Pick(const reg_t& t) { return t.m[Pos]; }
		template <bool A2, int N2>
		static void Store(value_t* dst, const reg_t& t, BConst<A2>, IConst<N2>) {
			static_assert(N2<=N, "");
			for(int i=0 ; i<N2+1 ; i++)
				*dst++ = t.m[i];
		}
		static value_t SumUp(const reg_t& t) {
			value_t sum = t.m[0];
			for(int i=1 ; i<capacity ; i++)
				sum += t.m[i];
			return sum;
		}
		template <class T2, bool A2>
		static reg_t Cast(const Data<T2,N,A2>& t) {
			reg_t ret;
			for(int i=0 ; i<capacity ; i++)
				ret.m[i] = *reinterpret_cast<const value_t*>(&t.m[i]);
			return ret;
		}
		template <class T2, bool A2>
		static reg_t Convert(const Data<T2,N,A2>& t) {
			reg_t ret;
			for(int i=0 ; i<capacity ; i++)
				ret.m[i] = t.m[i];
			return ret;
		}
	};
	#undef DEF_OP
}
<commit_msg>raw: noexcept指定や足りないルーチンの追加など<commit_after>#pragma once

namespace frea {
	#define countof(a) (sizeof(a)/sizeof(a[0]))
	#define DEF_OP(func, op) \
		template <class R> \
		static auto func(const R& t0, const R& t1) noexcept { \
			R ret; \
			for(int i=0 ; i<int(countof(t0.m)) ; i++) \
				ret.m[i] = t0.m[i] op t1.m[i]; \
			return ret; \
		}
	template <class T, bool F>
	struct _info {
		static T OneV() noexcept { return ~0; }
		DEF_OP(And, &)
		DEF_OP(Or, |)
		DEF_OP(Xor, ^)
	};
	template <class T>
	struct _info<T, true> {
		static int32_t ToInt(float);
		static int64_t ToInt(double);
		template <class T2>
		using ToInt_t = decltype(ToInt(T2()));

		using i_type = _info<T,true>::ToInt_t<T>;
		using f_type = T;
		static f_type OneV() noexcept {
			const i_type tmp(~0);
			return *(f_type*)&tmp;
		}
		#define DEF_OPF(func, op) \
			template <class R> \
			static auto func(const R& t0, const R& t1) noexcept { \
				R ret; \
				for(int i=0 ; i<int(countof(t0.m)) ; i++) { \
					const i_type tmp = *reinterpret_cast<const i_type*>(&t0.m[i]) op \
										*reinterpret_cast<const i_type*>(&t1.m[i]); \
					ret.m[i] = *reinterpret_cast<const f_type*>(&tmp); \
				} \
				return ret; \
			}
		DEF_OPF(And, &)
		DEF_OPF(Or, |)
		DEF_OPF(Xor, ^)
		#undef DEF_OPF
	};
	template <class T, int N, bool A>
	struct info<Data<T,N,A>> : _info<T, std::is_floating_point<T>{}> {
		constexpr static int capacity = N;
		using base_t = _info<T, std::is_floating_point<T>{}>;
		using reg_t = Data<T,N,A>;
		using value_t = T;

		DEF_OP(Add, +)
		DEF_OP(Sub, -)
		DEF_OP(Mul, *)
		DEF_OP(Div, /)

		static auto Zero() noexcept { return reg_t(0); }
		static auto One() noexcept { return reg_t(base_t::OneV()); }
		static auto LoadU(const value_t* v) noexcept { return reg_t(v, std::false_type()); }
		static auto Load(const value_t* v) noexcept { return reg_t(v, std::true_type()); }
		static auto Set1(const value_t& v) noexcept { return reg_t(v); }
		template <std::size_t... Idx>
		static auto _Set(std::index_sequence<Idx...>, const value_t* ar) noexcept {
			return reg_t(ar[Idx]...);
		}
		template <class... Ts>
		static auto Set(const Ts&... ts) noexcept {
			// 一旦配列に格納して順序を逆転
			const value_t tmp[sizeof...(Ts)] = {static_cast<value_t>(ts)...};
			return _Set(seq::Reverse_t<std::make_index_sequence<sizeof...(Ts)>>(), tmp);
		}
		template <class... Ts>
		static auto SetR(const Ts&... ts) noexcept { return reg_t(ts...); }
		template <int Pos>
		static auto MaskH(IConst<Pos>) noexcept { return reg_t(TagMask, IConst<Pos>(), base_t::OneV()); }
		template <int Pos>
		static auto PickAt(IConst<Pos>) noexcept { return reg_t(TagSet, IConst<Pos>(), base_t::OneV()); }
		template <int Pos>
		static value_t Pick(const reg_t& t) noexcept { return t.m[Pos]; }
		template <bool A2, int N2>
		static void Store(value_t* dst, const reg_t& t, BConst<A2>, IConst<N2>) noexcept {
			static_assert(N2<N, "");
			for(int i=0 ; i<N2+1 ; i++)
				*dst++ = t.m[i];
		}
		static value_t SumUp(const reg_t& t) noexcept {
			value_t sum = t.m[0];
			for(int i=1 ; i<capacity ; i++)
				sum += t.m[i];
			return sum;
		}
		template <class T2, bool A2>
		static reg_t Cast(const Data<T2,N,A2>& t) noexcept {
			reg_t ret;
			for(int i=0 ; i<capacity ; i++)
				ret.m[i] = *reinterpret_cast<const value_t*>(&t.m[i]);
			return ret;
		}
		template <class T2, bool A2>
		static reg_t Convert(const Data<T2,N,A2>& t) noexcept {
			reg_t ret;
			for(int i=0 ; i<capacity ; i++)
				ret.m[i] = t.m[i];
			return ret;
		}
		static value_t GetMinValue(const reg_t& r) noexcept {
			value_t ret = r.m[0];
			for(int i=1 ; i<capacity ; i++)
				ret = std::min(ret, r.m[i]);
			return ret;
		}
		static value_t GetMaxValue(const reg_t& r) noexcept {
			value_t ret = r.m[0];
			for(int i=1 ; i<capacity ; i++)
				ret = std::max(ret, r.m[i]);
			return ret;
		}
		static bool Equal(const reg_t& r0, const reg_t& r1) noexcept {
			for(int i=0 ; i<capacity ; i++) {
				if(r0.m[i] != r1.m[i])
					return false;
			}
			return true;
		}
		static reg_t Min(const reg_t& m0, const reg_t& m1) noexcept {
			reg_t ret;
			for(int i=0 ; i<capacity ; i++)
				ret.m[i] = std::min(m0.m[i], m1.m[i]);
			return ret;
		}
		static reg_t Max(const reg_t& m0, const reg_t& m1) noexcept {
			reg_t ret;
			for(int i=0 ; i<capacity ; i++)
				ret.m[i] = std::max(m0.m[i], m1.m[i]);
			return ret;
		}
		static reg_t Absolute(const reg_t& r) noexcept {
			reg_t ret;
			for(int i=0 ; i<capacity ; i++)
				ret.m[i] = std::abs(r.m[i]);
			return ret;
		}
		static reg_t Lt(const reg_t& r0, const reg_t& r1) noexcept {
			reg_t ret;
			for(int i=0 ; i<capacity ; i++)
				ret.m[i] = (r0.m[i] < r1.m[i]) ? ~0 : 0;
			return ret;
		}
		static reg_t Sqrt(const reg_t& r) noexcept {
			reg_t ret;
			for(int i=0 ; i<capacity ; i++)
				ret.m[i] = std::sqrt(r.m[i]);
			return ret;
		}
		static bool IsNaN(const reg_t& r) noexcept {
			for(int i=0 ; i<capacity ; i++) {
				if(r.m[i] != r.m[i])
					return true;
			}
			return false;
		}
		static bool IsOutstanding(const reg_t& r) noexcept {
			for(int i=0 ; i<capacity ; i++) {
				const auto& v = r.m[i];
				if(v!=v || std::abs(v)>=std::numeric_limits<value_t>::infinity())
					return true;
			}
			return false;
		}
		static value_t Reciprocal(const value_t& v) noexcept {
			return 1 / v;
		}
		static reg_t Reciprocal(const reg_t& r) noexcept {
			reg_t ret;
			for(int i=0 ; i<capacity ; i++)
				ret.m[i] = 1/r.m[i];
			return ret;
		}
		static reg_t Cross(const reg_t& a, const reg_t& b) noexcept {
			reg_t c;
			c.m[0] = a.m[1]*b.m[2] - a.m[2]*b.m[1];
			c.m[1] = a.m[2]*b.m[0] - a.m[0]*b.m[2];
			c.m[2] = a.m[0]*b.m[1] - a.m[1]*b.m[0];
			return c;
		}
	};
	#undef DEF_OP
}
<|endoftext|>


<commit_before>#pragma once

#include <cassert>
#include <cstring>
#include <string>
#include <unordered_map>

namespace xmlpp {
enum class entity_type { tag };

/**
 * @brief A parser adhering to SAX inteface.
 *
 * The class itself acts as an iterator, a foward one. So each
 * time you call next() (or operator++()) it will advance to next
 * entity, in a Depth first approach.
 */
class sax {
public:
  static constexpr const char *BLANKS = " \t\n\r";
  /**
   * @brief constructor that takes a c-string with the content.
   */
  sax(const char *code) {
    m_code = code;
    next();
  }

  bool next() {
    using namespace std;
    ignoreBlanks();
    if (*m_code == '<') {
      nextTag();
    } else if (strchr(BLANKS, *m_code) == nullptr) {
      throw runtime_error("Invalid char '"s + *m_code + "'");
    }
    return true;
  }

  /**
   * @brief returns the type of the current node.
   */
  entity_type type() const { return entity_type::tag; }

  /**
   * @brief Returns the value of the current node.
   *
   * The meaning of value is:
   * | type() | Meaning                                    |
   * | ------ | ------------------------------------------ |
   * | tag    | the name of tag ("<root/>"'s name is root) |
   */
  const std::string &value() const { return m_value; }

  /**
   * @brief the type of the parameters map.
   *
   * The underline type is implementation defined. Please use the aliased type.
   * We guaranteed that it defines an iterator, the operator[], the begin(),
   * end(), count() and size() and is able to be used with range-for.
   */
  using params_map = std::unordered_map<std::string, std::string>;

  /**
   * @brief Return the current parameters.
   *
   * The reference is valid until the next call of next() or operator++().
   */
  const params_map &params() const { return m_params; }

private:
  const char *m_code;
  std::string m_value;
  params_map m_params;

private:
  void nextTag() {
    using namespace std;
    assert(*m_code == '<');
    auto tag_beg = ++m_code;
    for (; *m_code != 0; ++m_code) {
      if (*m_code == '>' || *m_code == '/') {
        m_value.assign(tag_beg, m_code);
        return;
      } else if (strchr(BLANKS, *m_code)) {
        m_value.assign(tag_beg, m_code);
        goto PARAM_NAME;
      }
    }
    throw runtime_error("Unclosed tag.");
  PARAM_NAME:
    ignoreBlanks();
    string pname = "";
    auto pname_beg = m_code++;
    for (; *m_code != 0; ++m_code) {
      if (*m_code == '>' || *m_code == '/') {
        return;
      }
      if (*m_code == '=' || strchr(BLANKS, *m_code)) {
        if (m_code == pname_beg) {
          throw runtime_error(
              "Invalid Parameter. A name is expected before the '='");
        }
        pname.assign(pname_beg, m_code);
        goto PARAM_VALUE;
      }
    }
    throw runtime_error("Unclosed tag.");
  PARAM_VALUE:
    ignoreBlanks();
    if (*m_code != '=') {
      m_params[pname] = pname;
      goto PARAM_NAME;
    }
    ++m_code;
    ignoreBlanks();
    if (!strchr("\"\'", *m_code)) {
      throw runtime_error("Invalid Parameter '" + pname +
                          "'. The parameter value must be "
                          "surrounded by \' or \", we got: '" +
                          *m_code + "'");
    }
    char endToken = *m_code++;
    auto pvalue_beg = m_code++;
    for (; *m_code != 0; ++m_code) {
      if (*m_code == '>') {
        throw runtime_error("Expected a \' or \" before <");
      }
      if (*m_code == endToken) {
        m_params[pname].assign(pvalue_beg, m_code);
        ++m_code;
        goto PARAM_NAME;
      }
    }
    throw runtime_error("Unclosed tag.");
  }

  void ignoreBlanks() {
    while (strchr(BLANKS, *m_code)) {
      ++m_code;
    }
  }
};
}
<commit_msg>Refactored nextTag to move parameter parsing to its own function.<commit_after>#pragma once

#include <cassert>
#include <cstring>
#include <string>
#include <unordered_map>

namespace xmlpp {
enum class entity_type { tag };

/**
 * @brief A parser adhering to SAX inteface.
 *
 * The class itself acts as an iterator, a foward one. So each
 * time you call next() (or operator++()) it will advance to next
 * entity, in a Depth first approach.
 */
class sax {
public:
  static constexpr const char *BLANKS = " \t\n\r";
  /**
   * @brief constructor that takes a c-string with the content.
   */
  sax(const char *code) {
    m_code = code;
    next();
  }

  bool next() {
    using namespace std;
    ignoreBlanks();
    if (*m_code == '<') {
      nextTag();
    } else if (strchr(BLANKS, *m_code) == nullptr) {
      throw runtime_error("Invalid char '"s + *m_code + "'");
    }
    return true;
  }

  /**
   * @brief returns the type of the current node.
   */
  entity_type type() const { return entity_type::tag; }

  /**
   * @brief Returns the value of the current node.
   *
   * The meaning of value is:
   * | type() | Meaning                                    |
   * | ------ | ------------------------------------------ |
   * | tag    | the name of tag ("<root/>"'s name is root) |
   */
  const std::string &value() const { return m_value; }

  /**
   * @brief the type of the parameters map.
   *
   * The underline type is implementation defined. Please use the aliased type.
   * We guaranteed that it defines an iterator, the operator[], the begin(),
   * end(), count() and size() and is able to be used with range-for.
   */
  using params_map = std::unordered_map<std::string, std::string>;

  /**
   * @brief Return the current parameters.
   *
   * The reference is valid until the next call of next() or operator++().
   */
  const params_map &params() const { return m_params; }

private:
  const char *m_code;
  std::string m_value;
  params_map m_params;

private:
  void nextTag() {
    using namespace std;
    assert(*m_code == '<');
    auto tag_beg = ++m_code;
    for (; *m_code != 0; ++m_code) {
      if (strchr(BLANKS, *m_code) || *m_code == '>' || *m_code == '/') {
        m_value.assign(tag_beg, m_code);
        parameters();
        return;
      }
    }
    throw runtime_error("Unclosed tag.");
  }

  void parameters() {
    using namespace std;
  PARAM_NAME:
    ignoreBlanks();
    string pname = "";
    auto pname_beg = m_code++;
    for (; *m_code != 0; ++m_code) {
      if (*m_code == '>' || *m_code == '/') {
        return;
      }
      if (*m_code == '=' || strchr(BLANKS, *m_code)) {
        if (m_code == pname_beg) {
          throw runtime_error(
              "Invalid Parameter. A name is expected before the '='");
        }
        pname.assign(pname_beg, m_code);
        goto PARAM_VALUE;
      }
    }
    throw runtime_error("Expected close tag or parameter definition");
  PARAM_VALUE:
    ignoreBlanks();
    if (*m_code != '=') {
      m_params[pname] = pname;
      goto PARAM_NAME;
    }
    ++m_code;
    ignoreBlanks();
    if (!strchr("\"\'", *m_code)) {
      throw runtime_error("Invalid Parameter '" + pname +
                          "'. The parameter value must be "
                          "surrounded by \' or \", we got: '" +
                          *m_code + "'");
    }
    char endToken = *m_code++;
    auto pvalue_beg = m_code++;
    for (; *m_code != 0; ++m_code) {
      if (*m_code == '>') {
        throw runtime_error("Expected a \' or \" before <");
      }
      if (*m_code == endToken) {
        m_params[pname].assign(pvalue_beg, m_code);
        ++m_code;
        goto PARAM_NAME;
      }
    }
    throw runtime_error("Unclosed parameter value");
  }

  void ignoreBlanks() {
    while (strchr(BLANKS, *m_code)) {
      ++m_code;
    }
  }
};
}
<|endoftext|>