<commit_before>/************************************************************************/
/*                                                                      */
/*               Copyright 1998-2002 by Ullrich Koethe                  */
/*       Cognitive Systems Group, University of Hamburg, Germany        */
/*                                                                      */
/*    This file is part of the VIGRA computer vision library.           */
/*    The VIGRA Website is                                              */
/*        http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/      */
/*    Please direct questions, bug reports, and contributions to        */
/*        ullrich.koethe@iwr.uni-heidelberg.de    or                    */
/*        vigra@informatik.uni-hamburg.de                               */
/*                                                                      */
/*    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.                                   */
/*                                                                      */
/************************************************************************/

#ifndef VIGRA_METAPROGRAMMING_HXX
#define VIGRA_METAPROGRAMMING_HXX

#include "config.hxx"
#include <climits>
#include <limits>

namespace vigra {

template <int N>
class MetaInt
{
  public:
    enum { value = N };
};

struct VigraTrueType
{
   enum { asBool = true };
};

struct VigraFalseType
{
    enum { asBool = false };
};

/**  \addtogroup MultiArrayTags Multi-dimensional Array Tags
      Meta-programming tags to mark array's as strided or unstrided.
*/

//@{

/********************************************************/
/*                                                      */
/*                   StridedArrayTag                    */
/*                                                      */
/********************************************************/

/** tag for marking a MultiArray strided.

\#include
\<vigra/multi_array.hxx\>

Namespace: vigra
*/
struct StridedArrayTag {};

/********************************************************/
/*                                                      */
/*                  UnstridedArrayTag                   */
/*                                                      */
/********************************************************/

/** tag for marking a MultiArray unstrided.

\#include
\<vigra/multi_array.hxx\>

Namespace: vigra
*/
struct UnstridedArrayTag {};

template<class T>
class TypeTraits
{
  public:
    typedef VigraFalseType isConst;
    typedef VigraFalseType isPOD;
    typedef VigraFalseType isBuiltinType;
};

#ifndef NO_PARTIAL_TEMPLATE_SPECIALIZATION

template<class T>
class TypeTraits<T const>
: public TypeTraits<T>
{
  public:
    typedef VigraTrueType isConst;
};

template<class T>
class TypeTraits<T *>
{
  public:
    typedef VigraFalseType isConst;
    typedef VigraTrueType isPOD;
    typedef VigraTrueType isBuiltinType;
};

template<class T>
class TypeTraits<T const *>
{
  public:
    typedef VigraFalseType isConst;
    typedef VigraTrueType isPOD;
    typedef VigraTrueType isBuiltinType;
};

#endif // NO_PARTIAL_TEMPLATE_SPECIALIZATION

namespace detail {

template <int size>
struct SizeToType;

} // namespace detail

#define VIGRA_TYPE_TRAITS(type, size) \
template<> \
class TypeTraits<type> \
{ \
  public: \
    typedef VigraFalseType isConst; \
    typedef VigraTrueType isPOD; \
    typedef VigraTrueType isBuiltinType; \
    typedef char TypeToSize[size]; \
}; \
 \
namespace detail { \
  TypeTraits<type>::TypeToSize * typeToSize(type); \
  \
  template <> \
  struct SizeToType<size> \
  { \
      typedef type result; \
  }; \
}

VIGRA_TYPE_TRAITS(char, 1)
VIGRA_TYPE_TRAITS(signed char, 2)
VIGRA_TYPE_TRAITS(unsigned char, 3)
VIGRA_TYPE_TRAITS(short, 4)
VIGRA_TYPE_TRAITS(unsigned short, 5)
VIGRA_TYPE_TRAITS(int, 6)
VIGRA_TYPE_TRAITS(unsigned int, 7)
VIGRA_TYPE_TRAITS(long, 8)
VIGRA_TYPE_TRAITS(unsigned long, 9)
VIGRA_TYPE_TRAITS(float, 10)
VIGRA_TYPE_TRAITS(double, 11)
VIGRA_TYPE_TRAITS(long double, 12)
#ifdef LLONG_MAX
VIGRA_TYPE_TRAITS(long long, 13)
VIGRA_TYPE_TRAITS(unsigned long long, 14)
#endif

#undef VIGRA_TYPE_TRAITS

//@}

template <class A>
struct Not;

template <>
struct Not<VigraTrueType>
{
    typedef VigraFalseType result;
    static const bool boolResult = false;
};

template <>
struct Not<VigraFalseType>
{
    typedef VigraTrueType result;
    static const bool boolResult = true;
};

template <class L, class R>
struct And;

template <>
struct And<VigraFalseType, VigraFalseType>
{
    typedef VigraFalseType result;
    static const bool boolResult = false;
};

template <>
struct And<VigraFalseType, VigraTrueType>
{
    typedef VigraFalseType result;
    static const bool boolResult = false;
};

template <>
struct And<VigraTrueType, VigraFalseType>
{
    typedef VigraFalseType result;
    static const bool boolResult = false;
};

template <>
struct And<VigraTrueType, VigraTrueType>
{
    typedef VigraTrueType result;
    static const bool boolResult = true;
};

template <class L, class R>
struct Or;

template <>
struct Or<VigraFalseType, VigraFalseType>
{
    typedef VigraFalseType result;
    static const bool boolResult = false;
};

template <>
struct Or<VigraTrueType, VigraFalseType>
{
    typedef VigraTrueType result;
    static const bool boolResult = true;
};

template <>
struct Or<VigraFalseType, VigraTrueType>
{
    typedef VigraTrueType result;
    static const bool boolResult = true;
};

template <>
struct Or<VigraTrueType, VigraTrueType>
{
    typedef VigraTrueType result;
    static const bool boolResult = true;
};

#ifndef NO_PARTIAL_TEMPLATE_SPECIALIZATION

template <class PREDICATE, class TRUECASE, class FALSECASE>
struct If;

template <class TRUECASE, class FALSECASE>
struct If<VigraTrueType, TRUECASE, FALSECASE>
{
    typedef TRUECASE type;
};

template <class TRUECASE, class FALSECASE>
struct If<VigraFalseType, TRUECASE, FALSECASE>
{
    typedef FALSECASE type;
};

template <bool PREDICATE, class TRUECASE, class FALSECASE>
struct IfBool;

template <class TRUECASE, class FALSECASE>
struct IfBool<true, TRUECASE, FALSECASE>
{
    typedef TRUECASE type;
};

template <class TRUECASE, class FALSECASE>
struct IfBool<false, TRUECASE, FALSECASE>
{
    typedef FALSECASE type;
};

template <class L, class R>
struct IsSameType
{
    typedef VigraFalseType result;
    static const bool boolResult = false;
};

template <class T>
struct IsSameType<T, T>
{
    typedef VigraTrueType result;
    static const bool boolResult = true;
};

template <class DERIVED, class BASE>
struct IsDerivedFrom
{
    typedef char falseResult[1];
    typedef char trueResult[2];

    static falseResult * testIsDerivedFrom(...);
    static trueResult * testIsDerivedFrom(BASE const *);

    enum { resultSize = sizeof(*testIsDerivedFrom((DERIVED const *)0)) };

    static const bool boolResult = (resultSize == 2);
    typedef typename
        IfBool<boolResult, VigraTrueType, VigraFalseType>::type
        result;
};

#endif // NO_PARTIAL_TEMPLATE_SPECIALIZATION

} // namespace vigra

#endif /* VIGRA_METAPROGRAMMING_HXX */
<commit_msg>added has_result_type; unified API of meta-ptogramming functions<commit_after>/************************************************************************/
/*                                                                      */
/*               Copyright 1998-2002 by Ullrich Koethe                  */
/*       Cognitive Systems Group, University of Hamburg, Germany        */
/*                                                                      */
/*    This file is part of the VIGRA computer vision library.           */
/*    The VIGRA Website is                                              */
/*        http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/      */
/*    Please direct questions, bug reports, and contributions to        */
/*        ullrich.koethe@iwr.uni-heidelberg.de    or                    */
/*        vigra@informatik.uni-hamburg.de                               */
/*                                                                      */
/*    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.                                   */
/*                                                                      */
/************************************************************************/

#ifndef VIGRA_METAPROGRAMMING_HXX
#define VIGRA_METAPROGRAMMING_HXX

#include "config.hxx"
#include <climits>
#include <limits>

namespace vigra {

template <int N>
class MetaInt
{
  public:
    enum { value = N };
};

struct VigraTrueType
{
   enum { asBool = true };
};

struct VigraFalseType
{
    enum { asBool = false };
};

/**  \addtogroup MultiArrayTags Multi-dimensional Array Tags
      Meta-programming tags to mark array's as strided or unstrided.
*/

//@{

/********************************************************/
/*                                                      */
/*                   StridedArrayTag                    */
/*                                                      */
/********************************************************/

/** tag for marking a MultiArray strided.

\#include
\<vigra/multi_array.hxx\>

Namespace: vigra
*/
struct StridedArrayTag {};

/********************************************************/
/*                                                      */
/*                  UnstridedArrayTag                   */
/*                                                      */
/********************************************************/

/** tag for marking a MultiArray unstrided.

\#include
\<vigra/multi_array.hxx\>

Namespace: vigra
*/
struct UnstridedArrayTag {};

template<class T>
class TypeTraits
{
  public:
    typedef VigraFalseType isConst;
    typedef VigraFalseType isPOD;
    typedef VigraFalseType isBuiltinType;
};

#ifndef NO_PARTIAL_TEMPLATE_SPECIALIZATION

template<class T>
class TypeTraits<T const>
: public TypeTraits<T>
{
  public:
    typedef VigraTrueType isConst;
};

template<class T>
class TypeTraits<T *>
{
  public:
    typedef VigraFalseType isConst;
    typedef VigraTrueType isPOD;
    typedef VigraTrueType isBuiltinType;
};

template<class T>
class TypeTraits<T const *>
{
  public:
    typedef VigraFalseType isConst;
    typedef VigraTrueType isPOD;
    typedef VigraTrueType isBuiltinType;
};

#endif // NO_PARTIAL_TEMPLATE_SPECIALIZATION

namespace detail {

template <int size>
struct SizeToType;

} // namespace detail

#define VIGRA_TYPE_TRAITS(type, size) \
template<> \
class TypeTraits<type> \
{ \
  public: \
    typedef VigraFalseType isConst; \
    typedef VigraTrueType isPOD; \
    typedef VigraTrueType isBuiltinType; \
    typedef char TypeToSize[size]; \
}; \
 \
namespace detail { \
  TypeTraits<type>::TypeToSize * typeToSize(type); \
  \
  template <> \
  struct SizeToType<size> \
  { \
      typedef type result; \
  }; \
}

VIGRA_TYPE_TRAITS(char, 1)
VIGRA_TYPE_TRAITS(signed char, 2)
VIGRA_TYPE_TRAITS(unsigned char, 3)
VIGRA_TYPE_TRAITS(short, 4)
VIGRA_TYPE_TRAITS(unsigned short, 5)
VIGRA_TYPE_TRAITS(int, 6)
VIGRA_TYPE_TRAITS(unsigned int, 7)
VIGRA_TYPE_TRAITS(long, 8)
VIGRA_TYPE_TRAITS(unsigned long, 9)
VIGRA_TYPE_TRAITS(float, 10)
VIGRA_TYPE_TRAITS(double, 11)
VIGRA_TYPE_TRAITS(long double, 12)
#ifdef LLONG_MAX
VIGRA_TYPE_TRAITS(long long, 13)
VIGRA_TYPE_TRAITS(unsigned long long, 14)
#endif

#undef VIGRA_TYPE_TRAITS

//@}

template <class A>
struct Not;

template <>
struct Not<VigraTrueType>
{
    typedef VigraFalseType result;        // deprecated
    static const bool boolResult = false; // deprecated
    typedef VigraFalseType type;
    static const bool value = false;
};

template <>
struct Not<VigraFalseType>
{
    typedef VigraTrueType result;        // deprecated
    static const bool boolResult = true; // deprecated
    typedef VigraTrueType type;
    static const bool value = true;
};

template <class L, class R>
struct And;

template <>
struct And<VigraFalseType, VigraFalseType>
{
    typedef VigraFalseType result;        // deprecated
    static const bool boolResult = false; // deprecated
    typedef VigraFalseType type;
    static const bool value = false;
};

template <>
struct And<VigraFalseType, VigraTrueType>
{
    typedef VigraFalseType result;        // deprecated
    static const bool boolResult = false; // deprecated
    typedef VigraFalseType type;
    static const bool value = false;
};

template <>
struct And<VigraTrueType, VigraFalseType>
{
    typedef VigraFalseType result;        // deprecated
    static const bool boolResult = false; // deprecated
    typedef VigraFalseType type;
    static const bool value = false;
};

template <>
struct And<VigraTrueType, VigraTrueType>
{
    typedef VigraTrueType result;        // deprecated
    static const bool boolResult = true; // deprecated
    typedef VigraTrueType type;
    static const bool value = true;
};

template <class L, class R>
struct Or;

template <>
struct Or<VigraFalseType, VigraFalseType>
{
    typedef VigraFalseType result;        // deprecated
    static const bool boolResult = false; // deprecated
    typedef VigraFalseType type;
    static const bool value = false;
};

template <>
struct Or<VigraTrueType, VigraFalseType>
{
    typedef VigraTrueType result;        // deprecated
    static const bool boolResult = true; // deprecated
    typedef VigraTrueType type;
    static const bool value = true;
};

template <>
struct Or<VigraFalseType, VigraTrueType>
{
    typedef VigraTrueType result;        // deprecated
    static const bool boolResult = true; // deprecated
    typedef VigraTrueType type;
    static const bool value = true;
};

template <>
struct Or<VigraTrueType, VigraTrueType>
{
    typedef VigraTrueType result;        // deprecated
    static const bool boolResult = true; // deprecated
    typedef VigraTrueType type;
    static const bool value = true;
};

#ifndef NO_PARTIAL_TEMPLATE_SPECIALIZATION

template <class PREDICATE, class TRUECASE, class FALSECASE>
struct If;

template <class TRUECASE, class FALSECASE>
struct If<VigraTrueType, TRUECASE, FALSECASE>
{
    typedef TRUECASE type;
};

template <class TRUECASE, class FALSECASE>
struct If<VigraFalseType, TRUECASE, FALSECASE>
{
    typedef FALSECASE type;
};

template <bool PREDICATE, class TRUECASE, class FALSECASE>
struct IfBool;

template <class TRUECASE, class FALSECASE>
struct IfBool<true, TRUECASE, FALSECASE>
{
    typedef TRUECASE type;
};

template <class TRUECASE, class FALSECASE>
struct IfBool<false, TRUECASE, FALSECASE>
{
    typedef FALSECASE type;
};

template <class L, class R>
struct IsSameType
{
    typedef VigraFalseType result;        // deprecated
    static const bool boolResult = false; // deprecated
    typedef VigraFalseType type;
    static const bool value = false;
};

template <class T>
struct IsSameType<T, T>
{
    typedef VigraTrueType result;        // deprecated
    static const bool boolResult = true; // deprecated
    typedef VigraTrueType type;
    static const bool value = true;
};

#endif // NO_PARTIAL_TEMPLATE_SPECIALIZATION

template <class DERIVED, class BASE>
struct IsDerivedFrom
{
    typedef char falseResult[1];
    typedef char trueResult[2];

    static falseResult * testIsDerivedFrom(...);
    static trueResult * testIsDerivedFrom(BASE const *);

    enum { resultSize = sizeof(*testIsDerivedFrom((DERIVED const *)0)) };

    static const bool value = (resultSize == 2);
    typedef typename
        IfBool<value, VigraTrueType, VigraFalseType>::type
        type;

    static const bool boolResult = value; // deprecated
    typedef type result;                  // deprecated
};

template <class T>
struct has_result_type
{
    typedef char falseResult[1];
    typedef char trueResult[2];

    static falseResult * test(...);
    template <class U>
    static trueResult * test(U *, typename U::result_type * = 0);

    enum { resultSize = sizeof(*test((T*)0)) };

    static const bool value = (resultSize == 2);
    typedef typename
        IfBool<value, VigraTrueType, VigraFalseType>::type
        type;
};

} // namespace vigra

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


<commit_before>#include "Matrix33.hpp"
#include "Matrix44.hpp"
#include "Vector3.hpp"

using namespace coffeemill;
typedef RealVector3 Realvec;
typedef RealMatrix33 Matrix3;
typedef RealMatrix44 Matrix4;

int main()
{
    Realvec v1;
    Realvec v2(1e0);
    Realvec v3(1e0, 2e0, 3e0);
    Realvec v4(v2);
    Realvec v5(v2 + v3);
    Realvec v6(v2 - v3);
    Realvec v7(v2*2e0);
    Realvec v8(2e0*v2);
    Realvec v9(v2/2e0);
    Realvec vv5;
    Realvec vv6;
    Realvec vv7;
    Realvec vv8;
    Realvec vv9;
    vv5 = v2 + v3;
    vv6 = v2 - v3;
    vv7 = v2 * 2e0;
    vv8 = 2e0 * v2;
    vv9 = v2 / 2e0;

    std::cout << "v1                 : " << v1 << std::endl;
    std::cout << "v2(1e0)            : " << v2 << std::endl;
    std::cout << "v3(1e0, 2e0, 3e0)  : " << v3 << std::endl;
    std::cout << "v4(v2)             : " << v4 << std::endl;
    std::cout << "v5(v2+v3)          : " << v5 << std::endl;
    std::cout << "v6(v2-v3)          : " << v6 << std::endl;
    std::cout << "v7(v2*2e0)         : " << v7 << std::endl;
    std::cout << "v8(2e0*v2)         : " << v8 << std::endl;
    std::cout << "v9(v2/2e0)         : " << v9 << std::endl;
    std::cout << "v5 = v2 + v3       : " << vv5 << std::endl;
    std::cout << "v6 = v2 - v3       : " << vv6 << std::endl;
    std::cout << "v7 = v2 * 2e0      : " << vv7 << std::endl;
    std::cout << "v8 = 2e0 * v2      : " << vv8 << std::endl;
    std::cout << "v9 = v2 / 2e0      : " << vv9 << std::endl;
    std::cout << "length(v2)         : " << length(v2) << std::endl;
    std::cout << "len_square(v2)     : " << len_square(v2) << std::endl;
    std::cout << "dot_prod(v2, v3)   : " << dot_prod(v2, v3) << std::endl;
    Realvec temp;
    temp = cross_prod(v2, v3);
    std::cout << "cross_prod(v2, v3) : " << cross_prod(v2, v3) << std::endl;

//     Matrix3 m1;
//     Matrix3 m2(2e0);
//     Matrix3 m4(m2);
//     Matrix3 m5(m2 + m2);
//     Matrix3 m6(m2 - m2);
//     Matrix3 m7(m2*2e0);
//     Matrix3 m8(2e0*m2);
//     Matrix3 m9(m2/2e0);
//
//     std::cout << "m1                 : " << std::endl << m1 << std::endl;
//     std::cout << "m2(1e0)            : " << std::endl << m2 << std::endl;
//     std::cout << "m4(m2)             : " << std::endl << m4 << std::endl;
//     std::cout << "m5(m2+m2)          : " << std::endl << m5 << std::endl;
//     std::cout << "m6(m2-m2)          : " << std::endl << m6 << std::endl;
//     std::cout << "m7(m2*2e0)         : " << std::endl << m7 << std::endl;
//     std::cout << "m8(2e0*m2)         : " << std::endl << m8 << std::endl;
//     std::cout << "m9(m2/2e0)         : " << std::endl << m9 << std::endl;
//
//     m5 = m2 + m2;
//     m6 = m2 - m2;
//     m7 = m2 * 2e0;
//     m8 = 2e0 * m2;
//     m9 = m2 / 2e0;
//
//     std::cout << "m5 = m2 + m2       : "<< std::endl << m5 << std::endl;
//     std::cout << "m6 = m2 - m2       : "<< std::endl << m6 << std::endl;
//     std::cout << "m7 = m2 * 2e0      : "<< std::endl << m7 << std::endl;
//     std::cout << "m8 = 2e0 * m2      : "<< std::endl << m8 << std::endl;
//     std::cout << "m9 = m2 / 2e0      : "<< std::endl << m9 << std::endl;
//
//     m1(0,0) = 1e0;
//     m1(0,1) = 1e0;
//     m1(0,2) = 1e0;
//     m1(1,1) = 1e0;
//     m1(1,2) = 1e0;
//     m1(2,2) = 1e0;
//     std::cout << "m1: " << std::endl << m1 << std::endl;
//     Matrix3 m3temp;
//     m3temp = m1 * m2;
//     std::cout << "m1 * m2" << std::endl << m3temp << std::endl;
//     Matrix3 m10(m1 * m2);
//     std::cout << "m10(m1*m2): " << std::endl << m10 << std::endl;

    Matrix4 m1;
    Matrix4 m2(2e0);
    Matrix4 m3(1e0);
    Matrix4 m4(m2);
    Matrix4 m5(m2 + m3);
    Matrix4 m6(m2 - m3);
    Matrix4 m7(m2*2e0);
    Matrix4 m8(2e0*m2);
    Matrix4 m9(m2/2e0);

    std::cout << "m1                 : " << std::endl << m1 << std::endl;
    std::cout << "m2(1e0)            : " << std::endl << m2 << std::endl;
    std::cout << "m4(m2)             : " << std::endl << m4 << std::endl;
    std::cout << "m5(m2+m2)          : " << std::endl << m5 << std::endl;
    std::cout << "m6(m2-m2)          : " << std::endl << m6 << std::endl;
    std::cout << "m7(m2*2e0)         : " << std::endl << m7 << std::endl;
    std::cout << "m8(2e0*m2)         : " << std::endl << m8 << std::endl;
    std::cout << "m9(m2/2e0)         : " << std::endl << m9 << std::endl;

    m5 = m2 + m2;
    m6 = m2 - m2;
    m7 = m2 * 2e0;
    m8 = 2e0 * m2;
    m9 = m2 / 2e0;

    std::cout << "m5 = m2 + m2       : " << std::endl << m5 << std::endl;
    std::cout << "m6 = m2 - m2       : " << std::endl << m6 << std::endl;
    std::cout << "m7 = m2 * 2e0      : " << std::endl << m7 << std::endl;
    std::cout << "m8 = 2e0 * m2      : " << std::endl << m8 << std::endl;
    std::cout << "m9 = m2 / 2e0      : " << std::endl << m9 << std::endl;

    m1(0,0) = 1e0;
    m1(0,1) = 1e0;
    m1(0,2) = 1e0;
    m1(0,3) = 1e0;
    m1(1,1) = 1e0;
    m1(1,2) = 1e0;
    m1(1,3) = 1e0;
    m1(2,2) = 1e0;
    m1(2,3) = 1e0;
    m1(3,3) = 1e0;
    std::cout << "m1: " << std::endl << m1 << std::endl;
    Matrix4 m4temp;
    m4temp = m1 * m2;
    std::cout << "m1 * m2" << std::endl << m4temp << std::endl;
    Matrix4 m10(m1 * m2);
    std::cout << "m10(m1*m2): " << std::endl << m10 << std::endl;

    return 0;
}
<commit_msg>testing<commit_after>#include "LinearAlgebra.hpp"

using namespace coffeemill;

int main()
{
    Realvec v1;
    Realvec v2(1e0);
    Realvec v3(1e0, 2e0, 3e0);
    Realvec v4(v2);
    Realvec v5(v2 + v3);
    Realvec v6(v2 - v3);
    Realvec v7(v2*2e0);
    Realvec v8(2e0*v2);
    Realvec v9(v2/2e0);
    Realvec vv5;
    Realvec vv6;
    Realvec vv7;
    Realvec vv8;
    Realvec vv9;
    vv5 = v2 + v3;
    vv6 = v2 - v3;
    vv7 = v2 * 2e0;
    vv8 = 2e0 * v2;
    vv9 = v2 / 2e0;

    std::cout << "v1                 : " << v1 << std::endl;
    std::cout << "v2(1e0)            : " << v2 << std::endl;
    std::cout << "v3(1e0, 2e0, 3e0)  : " << v3 << std::endl;
    std::cout << "v4(v2)             : " << v4 << std::endl;
    std::cout << "v5(v2+v3)          : " << v5 << std::endl;
    std::cout << "v6(v2-v3)          : " << v6 << std::endl;
    std::cout << "v7(v2*2e0)         : " << v7 << std::endl;
    std::cout << "v8(2e0*v2)         : " << v8 << std::endl;
    std::cout << "v9(v2/2e0)         : " << v9 << std::endl;
    std::cout << "v5 = v2 + v3       : " << vv5 << std::endl;
    std::cout << "v6 = v2 - v3       : " << vv6 << std::endl;
    std::cout << "v7 = v2 * 2e0      : " << vv7 << std::endl;
    std::cout << "v8 = 2e0 * v2      : " << vv8 << std::endl;
    std::cout << "v9 = v2 / 2e0      : " << vv9 << std::endl;
    std::cout << "length(v2)         : " << length(v2) << std::endl;
    std::cout << "len_square(v2)     : " << len_square(v2) << std::endl;
    std::cout << "dot_prod(v2, v3)   : " << dot_prod(v2, v3) << std::endl;
    Realvec temp;
    temp = cross_prod(v2, v3);
    std::cout << "cross_prod(v2, v3) : " << temp << std::endl;

//     Matrix3 m1;
//     Matrix3 m2(2e0);
//     Matrix3 m4(m2);
//     Matrix3 m5(m2 + m2);
//     Matrix3 m6(m2 - m2);
//     Matrix3 m7(m2*2e0);
//     Matrix3 m8(2e0*m2);
//     Matrix3 m9(m2/2e0);
//
//     std::cout << "m1                 : " << std::endl << m1 << std::endl;
//     std::cout << "m2(1e0)            : " << std::endl << m2 << std::endl;
//     std::cout << "m4(m2)             : " << std::endl << m4 << std::endl;
//     std::cout << "m5(m2+m2)          : " << std::endl << m5 << std::endl;
//     std::cout << "m6(m2-m2)          : " << std::endl << m6 << std::endl;
//     std::cout << "m7(m2*2e0)         : " << std::endl << m7 << std::endl;
//     std::cout << "m8(2e0*m2)         : " << std::endl << m8 << std::endl;
//     std::cout << "m9(m2/2e0)         : " << std::endl << m9 << std::endl;
//
//     m5 = m2 + m2;
//     m6 = m2 - m2;
//     m7 = m2 * 2e0;
//     m8 = 2e0 * m2;
//     m9 = m2 / 2e0;
//
//     std::cout << "m5 = m2 + m2       : "<< std::endl << m5 << std::endl;
//     std::cout << "m6 = m2 - m2       : "<< std::endl << m6 << std::endl;
//     std::cout << "m7 = m2 * 2e0      : "<< std::endl << m7 << std::endl;
//     std::cout << "m8 = 2e0 * m2      : "<< std::endl << m8 << std::endl;
//     std::cout << "m9 = m2 / 2e0      : "<< std::endl << m9 << std::endl;
//
//     m1(0,0) = 1e0;
//     m1(0,1) = 1e0;
//     m1(0,2) = 1e0;
//     m1(1,1) = 1e0;
//     m1(1,2) = 1e0;
//     m1(2,2) = 1e0;
//     std::cout << "m1: " << std::endl << m1 << std::endl;
//     Matrix3 m3temp;
//     m3temp = m1 * m2;
//     std::cout << "m1 * m2" << std::endl << m3temp << std::endl;
//     Matrix3 m10(m1 * m2);
//     std::cout << "m10(m1*m2): " << std::endl << m10 << std::endl;

    Matrix4 m1;
    Matrix4 m2(2e0);
    Matrix4 m3(1e0);
    Matrix4 m4(m2);
    Matrix4 m5(m2 + m3);
    Matrix4 m6(m2 - m3);
    Matrix4 m7(m2*2e0);
    Matrix4 m8(2e0*m2);
    Matrix4 m9(m2/2e0);

    std::cout << "m1                 : " << std::endl << m1 << std::endl;
    std::cout << "m2(1e0)            : " << std::endl << m2 << std::endl;
    std::cout << "m4(m2)             : " << std::endl << m4 << std::endl;
    std::cout << "m5(m2+m2)          : " << std::endl << m5 << std::endl;
    std::cout << "m6(m2-m2)          : " << std::endl << m6 << std::endl;
    std::cout << "m7(m2*2e0)         : " << std::endl << m7 << std::endl;
    std::cout << "m8(2e0*m2)         : " << std::endl << m8 << std::endl;
    std::cout << "m9(m2/2e0)         : " << std::endl << m9 << std::endl;

    m5 = m2 + m2;
    m6 = m2 - m2;
    m7 = m2 * 2e0;
    m8 = 2e0 * m2;
    m9 = m2 / 2e0;

    std::cout << "m5 = m2 + m2       : " << std::endl << m5 << std::endl;
    std::cout << "m6 = m2 - m2       : " << std::endl << m6 << std::endl;
    std::cout << "m7 = m2 * 2e0      : " << std::endl << m7 << std::endl;
    std::cout << "m8 = 2e0 * m2      : " << std::endl << m8 << std::endl;
    std::cout << "m9 = m2 / 2e0      : " << std::endl << m9 << std::endl;

    m1(0,0) = 1e0;
    m1(0,1) = 1e0;
    m1(0,2) = 1e0;
    m1(0,3) = 1e0;
    m1(1,1) = 1e0;
    m1(1,2) = 1e0;
    m1(1,3) = 1e0;
    m1(2,2) = 1e0;
    m1(2,3) = 1e0;
    m1(3,3) = 1e0;
    std::cout << "m1: " << std::endl << m1 << std::endl;
    Matrix4 m4temp;
    m4temp = m1 * m2;
    std::cout << "m1 * m2" << std::endl << m4temp << std::endl;
    Matrix4 m10(m1 * m2);
    std::cout << "m10(m1*m2): " << std::endl << m10 << std::endl;

    return 0;
}
<|endoftext|>


<commit_before>/**@file GSM/SIP Mobility Management, GSM 04.08. */
/*
* Copyright 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
* Copyright 2011 Range Networks, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Affero General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Affero General Public License for more details.

	You should have received a copy of the GNU Affero General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/

#include <Timeval.h>

#include "ControlCommon.h"
#include "MobilityManagement.h"
#include "SMSControl.h"
#include "CallControl.h"
#include "RRLPServer.h"

#include <GSMLogicalChannel.h>
#include <GSML3RRMessages.h>
#include <GSML3MMMessages.h>
#include <GSML3CCMessages.h>
#include <GSMConfig.h>

using namespace std;

#include <SIPInterface.h>
#include <SIPUtility.h>
#include <SIPMessage.h>
#include <SIPEngine.h>
#include <SubscriberRegistry.h>

using namespace SIP;

#include <Regexp.h>
#include <Logger.h>
#undef WARNING

using namespace GSM;
using namespace Control;

/** Controller for CM Service requests, dispatches out to multiple possible transaction controllers. */
void Control::CMServiceResponder(const L3CMServiceRequest* cmsrq, LogicalChannel* DCCH)
{
	assert(cmsrq);
	assert(DCCH);
	LOG(INFO) << *cmsrq;
	switch (cmsrq->serviceType().type()) {
		case L3CMServiceType::MobileOriginatedCall:
			MOCStarter(cmsrq,DCCH);
			break;
		case L3CMServiceType::ShortMessage:
			MOSMSController(cmsrq,DCCH);
			break;
		default:
			LOG(NOTICE) << "service not supported for " << *cmsrq;
			// Cause 0x20 means "serivce not supported".
			DCCH->send(L3CMServiceReject(0x20));
			DCCH->send(L3ChannelRelease());
	}
	// The transaction may or may not be cleared,
	// depending on the assignment type.
}

/** Controller for the IMSI Detach transaction, GSM 04.08 4.3.4. */
void Control::IMSIDetachController(const L3IMSIDetachIndication* idi, LogicalChannel* DCCH)
{
	assert(idi);
	assert(DCCH);
	LOG(INFO) << *idi;

	// The IMSI detach maps to a SIP unregister with the local Asterisk server.
	try {
		// FIXME -- Resolve TMSIs to IMSIs.
		if (idi->mobileID().type()==IMSIType) {
			SIPEngine engine(gConfig.getStr("SIP.Proxy.Registration").c_str(), idi->mobileID().digits());
			engine.unregister();
		}
	}
	catch(SIPTimeout) {
		LOG(ALERT) "SIP registration timed out.  Is Asterisk running?";
	}
	// No reponse required, so just close the channel.
	DCCH->send(L3ChannelRelease());
	// Many handsets never complete the transaction.
	// So force a shutdown of the channel.
	DCCH->send(HARDRELEASE);
}

/**
	Send a given welcome message from a given short code.
	@return true if it was sent
*/
bool sendWelcomeMessage(const char* messageName, const char* shortCodeName, const char *IMSI, LogicalChannel* DCCH, const char *whiteListCode = NULL)
{
	if (!gConfig.defines(messageName)) return false;
	LOG(INFO) << "sending " << messageName << " message to handset";
	ostringstream message;
	message << gConfig.getStr(messageName) << " IMSI:" << IMSI;
	if (whiteListCode) {
		message << ", white-list code: " << whiteListCode;
	}
	// This returns when delivery is acked in L3.
	deliverSMSToMS(
		gConfig.getStr(shortCodeName).c_str(),
		message.str().c_str(), "text/plain",
		random()%7,DCCH);
	return true;
}

/**
	Controller for the Location Updating transaction, GSM 04.08 4.4.4.
	@param lur The location updating request.
	@param DCCH The Dm channel to the MS, which will be released by the function.
*/
void Control::LocationUpdatingController(const L3LocationUpdatingRequest* lur, LogicalChannel* DCCH)
{
	assert(DCCH);
	assert(lur);
	LOG(INFO) << *lur;

	// The location updating request gets mapped to a SIP
	// registration with the Asterisk server.

	// We also allocate a new TMSI for every handset we encounter.
	// If the handset is allow to register it may receive a TMSI reassignment.

	// Resolve an IMSI and see if there's a pre-existing IMSI-TMSI mapping.
	// This operation will throw an exception, caught in a higher scope,
	// if it fails in the GSM domain.
	L3MobileIdentity mobileID = lur->mobileID();
	bool sameLAI = (lur->LAI() == gBTS.LAI());
	unsigned preexistingTMSI = resolveIMSI(sameLAI,mobileID,DCCH);
	const char *IMSI = mobileID.digits();
	// IMSIAttach set to true if this is a new registration.
	bool IMSIAttach = (preexistingTMSI==0);

	// We assign generate a TMSI for every new phone we see,
	// even if we don't actually assign it.
	unsigned newTMSI = 0;
	if (!preexistingTMSI) newTMSI = gTMSITable.assign(IMSI,lur);

	// Try to register the IMSI.
	// This will be set true if registration succeeded in the SIP world.
	bool success = false;
	try {
		SIPEngine engine(gConfig.getStr("SIP.Proxy.Registration").c_str(),IMSI);
		LOG(DEBUG) << "waiting for registration of " << IMSI << " on " << gConfig.getStr("SIP.Proxy.Registration");
		success = engine.Register(SIPEngine::SIPRegister);
	}
	catch(SIPTimeout) {
		LOG(ALERT) "SIP registration timed out.  Is the proxy running at " << gConfig.getStr("SIP.Proxy.Registration");
		// Reject with a "network failure" cause code, 0x11.
		DCCH->send(L3LocationUpdatingReject(0x11));
		// HACK -- wait long enough for a response
		// FIXME -- Why are we doing this?
		sleep(4);
		// Release the channel and return.
		DCCH->send(L3ChannelRelease());
		return;
	}

	// This allows us to configure Open Registration
	bool openRegistration = gConfig.defines("Control.LUR.OpenRegistration");

	// Query for IMEI?
	if (gConfig.defines("Control.LUR.QueryIMEI")) {
		DCCH->send(L3IdentityRequest(IMEIType));
		L3Message* msg = getMessage(DCCH);
		L3IdentityResponse *resp = dynamic_cast<L3IdentityResponse*>(msg);
		if (!resp) {
			if (msg) {
				LOG(WARNING) << "Unexpected message " << *msg;
				delete msg;
			}
			throw UnexpectedMessage();
		}
		LOG(INFO) << *resp;
		string new_imei = resp->mobileID().digits();
		if (!gTMSITable.IMEI(IMSI,new_imei.c_str())){
			LOG(WARNING) << "failed access to TMSITable";
		}

		//query subscriber registry for old imei, update if neccessary
		string name = string("IMSI") + IMSI;
		string old_imei = gSubscriberRegistry.imsiGet(name, "hardware");

		//if we have a new imei and either there's no old one, or it is different...
		if (!new_imei.empty() && (old_imei.empty() || old_imei != new_imei)){
			LOG(INFO) << "Updating IMSI" << IMSI << " to IMEI:" << new_imei;
			if (gSubscriberRegistry.imsiSet(name,"RRLPSupported", "1")) {
			 	LOG(INFO) << "SR RRLPSupported update problem";
			}
			if (gSubscriberRegistry.imsiSet(name,"hardware", new_imei)) {
				LOG(INFO) << "SR hardware update problem";
			}
		}
		delete msg;
	}

	// Query for classmark?
	if (IMSIAttach && gConfig.defines("Control.LUR.QueryClassmark")) {
		DCCH->send(L3ClassmarkEnquiry());
		L3Message* msg = getMessage(DCCH);
		L3ClassmarkChange *resp = dynamic_cast<L3ClassmarkChange*>(msg);
		if (!resp) {
			if (msg) {
				LOG(WARNING) << "Unexpected message " << *msg;
				delete msg;
			}
			throw UnexpectedMessage();
		}
		LOG(INFO) << *resp;
		const L3MobileStationClassmark2& classmark = resp->classmark();
		if (!gTMSITable.classmark(IMSI,classmark))
			LOG(WARNING) << "failed access to TMSITable";
		delete msg;
	}

	// We fail closed unless we're configured otherwise
	if (!success && !openRegistration) {
		LOG(INFO) << "registration FAILED: " << mobileID;
		DCCH->send(L3LocationUpdatingReject(gConfig.getNum("Control.LUR.UnprovisionedRejectCause")));
		if (!preexistingTMSI) {
			sendWelcomeMessage( "Control.LUR.FailedRegistration.Message",
				"Control.LUR.FailedRegistration.ShortCode", IMSI,DCCH);
		}
		// Release the channel and return.
		DCCH->send(L3ChannelRelease());
		return;
	}

	// If success is true, we had a normal registration.
	// Otherwise, we are here because of open registration.
	// Either way, we're going to register a phone if we arrive here.

	if (success) {
		LOG(INFO) << "registration SUCCESS: " << mobileID;
	} else {
		LOG(INFO) << "registration ALLOWED: " << mobileID;
	}

	// Send the "short name" and time-of-day.
	if (IMSIAttach && gConfig.defines("GSM.Identity.ShortName")) {
		DCCH->send(L3MMInformation(gConfig.getStr("GSM.Identity.ShortName").c_str()));
	}
	// Accept. Make a TMSI assignment, too, if needed.
	if (preexistingTMSI || !gConfig.defines("Control.LUR.SendTMSIs")) {
		DCCH->send(L3LocationUpdatingAccept(gBTS.LAI()));
	} else {
		assert(newTMSI);
		DCCH->send(L3LocationUpdatingAccept(gBTS.LAI(),newTMSI));
		// Wait for MM TMSI REALLOCATION COMPLETE (0x055b).
		L3Frame* resp = DCCH->recv(1000);
		// FIXME -- Actually check the response type.
		if (!resp) {
			LOG(NOTICE) << "no response to TMSI assignment";
		} else {
			LOG(INFO) << *resp;
		}
		delete resp;
	}

	if (gConfig.defines("Control.LUR.QueryRRLP")) {
		// Query for RRLP
		if (!sendRRLP(mobileID, DCCH)) {
			LOG(INFO) << "RRLP request failed";
		}
	}

	// If this is an IMSI attach, send a welcome message.
	if (IMSIAttach) {
		if (success) {
			sendWelcomeMessage( "Control.LUR.NormalRegistration.Message",
				"Control.LUR.NormalRegistration.ShortCode", IMSI, DCCH);
		} else {
			sendWelcomeMessage( "Control.LUR.OpenRegistration.Message",
				"Control.LUR.OpenRegistration.ShortCode", IMSI, DCCH);
		}
	}

	// Release the channel and return.
	DCCH->send(L3ChannelRelease());
	return;
}

// vim: ts=4 sw=4
<commit_msg>adding regex back into MobilityManagement for OpenRegistration. It's in the manual, we should have it in the code.<commit_after>/**@file GSM/SIP Mobility Management, GSM 04.08. */
/*
* Copyright 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
* Copyright 2011 Range Networks, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Affero General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Affero General Public License for more details.

	You should have received a copy of the GNU Affero General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/

#include <Timeval.h>

#include "ControlCommon.h"
#include "MobilityManagement.h"
#include "SMSControl.h"
#include "CallControl.h"
#include "RRLPServer.h"

#include <GSMLogicalChannel.h>
#include <GSML3RRMessages.h>
#include <GSML3MMMessages.h>
#include <GSML3CCMessages.h>
#include <GSMConfig.h>

using namespace std;

#include <SIPInterface.h>
#include <SIPUtility.h>
#include <SIPMessage.h>
#include <SIPEngine.h>
#include <SubscriberRegistry.h>

using namespace SIP;

#include <Regexp.h>
#include <Logger.h>
#undef WARNING

using namespace GSM;
using namespace Control;

/** Controller for CM Service requests, dispatches out to multiple possible transaction controllers. */
void Control::CMServiceResponder(const L3CMServiceRequest* cmsrq, LogicalChannel* DCCH)
{
	assert(cmsrq);
	assert(DCCH);
	LOG(INFO) << *cmsrq;
	switch (cmsrq->serviceType().type()) {
		case L3CMServiceType::MobileOriginatedCall:
			MOCStarter(cmsrq,DCCH);
			break;
		case L3CMServiceType::ShortMessage:
			MOSMSController(cmsrq,DCCH);
			break;
		default:
			LOG(NOTICE) << "service not supported for " << *cmsrq;
			// Cause 0x20 means "serivce not supported".
			DCCH->send(L3CMServiceReject(0x20));
			DCCH->send(L3ChannelRelease());
	}
	// The transaction may or may not be cleared,
	// depending on the assignment type.
}

/** Controller for the IMSI Detach transaction, GSM 04.08 4.3.4. */
void Control::IMSIDetachController(const L3IMSIDetachIndication* idi, LogicalChannel* DCCH)
{
	assert(idi);
	assert(DCCH);
	LOG(INFO) << *idi;

	// The IMSI detach maps to a SIP unregister with the local Asterisk server.
	try {
		// FIXME -- Resolve TMSIs to IMSIs.
		if (idi->mobileID().type()==IMSIType) {
			SIPEngine engine(gConfig.getStr("SIP.Proxy.Registration").c_str(), idi->mobileID().digits());
			engine.unregister();
		}
	}
	catch(SIPTimeout) {
		LOG(ALERT) "SIP registration timed out.  Is Asterisk running?";
	}
	// No reponse required, so just close the channel.
	DCCH->send(L3ChannelRelease());
	// Many handsets never complete the transaction.
	// So force a shutdown of the channel.
	DCCH->send(HARDRELEASE);
}

/**
	Send a given welcome message from a given short code.
	@return true if it was sent
*/
bool sendWelcomeMessage(const char* messageName, const char* shortCodeName, const char *IMSI, LogicalChannel* DCCH, const char *whiteListCode = NULL)
{
	if (!gConfig.defines(messageName)) return false;
	LOG(INFO) << "sending " << messageName << " message to handset";
	ostringstream message;
	message << gConfig.getStr(messageName) << " IMSI:" << IMSI;
	if (whiteListCode) {
		message << ", white-list code: " << whiteListCode;
	}
	// This returns when delivery is acked in L3.
	deliverSMSToMS(
		gConfig.getStr(shortCodeName).c_str(),
		message.str().c_str(), "text/plain",
		random()%7,DCCH);
	return true;
}

/**
	Controller for the Location Updating transaction, GSM 04.08 4.4.4.
	@param lur The location updating request.
	@param DCCH The Dm channel to the MS, which will be released by the function.
*/
void Control::LocationUpdatingController(const L3LocationUpdatingRequest* lur, LogicalChannel* DCCH)
{
	assert(DCCH);
	assert(lur);
	LOG(INFO) << *lur;

	// The location updating request gets mapped to a SIP
	// registration with the Asterisk server.

	// We also allocate a new TMSI for every handset we encounter.
	// If the handset is allow to register it may receive a TMSI reassignment.

	// Resolve an IMSI and see if there's a pre-existing IMSI-TMSI mapping.
	// This operation will throw an exception, caught in a higher scope,
	// if it fails in the GSM domain.
	L3MobileIdentity mobileID = lur->mobileID();
	bool sameLAI = (lur->LAI() == gBTS.LAI());
	unsigned preexistingTMSI = resolveIMSI(sameLAI,mobileID,DCCH);
	const char *IMSI = mobileID.digits();
	// IMSIAttach set to true if this is a new registration.
	bool IMSIAttach = (preexistingTMSI==0);

	// We assign generate a TMSI for every new phone we see,
	// even if we don't actually assign it.
	unsigned newTMSI = 0;
	if (!preexistingTMSI) newTMSI = gTMSITable.assign(IMSI,lur);

	// Try to register the IMSI.
	// This will be set true if registration succeeded in the SIP world.
	bool success = false;
	try {
		SIPEngine engine(gConfig.getStr("SIP.Proxy.Registration").c_str(),IMSI);
		LOG(DEBUG) << "waiting for registration of " << IMSI << " on " << gConfig.getStr("SIP.Proxy.Registration");
		success = engine.Register(SIPEngine::SIPRegister);
	}
	catch(SIPTimeout) {
		LOG(ALERT) "SIP registration timed out.  Is the proxy running at " << gConfig.getStr("SIP.Proxy.Registration");
		// Reject with a "network failure" cause code, 0x11.
		DCCH->send(L3LocationUpdatingReject(0x11));
		// HACK -- wait long enough for a response
		// FIXME -- Why are we doing this?
		sleep(4);
		// Release the channel and return.
		DCCH->send(L3ChannelRelease());
		return;
	}

	// This allows us to configure Open Registration
	bool openRegistration = false;
	if (gConfig.defines("Control.LUR.OpenRegistration")) {
		if (!gConfig.defines("Control.LUR.OpenRegistration.Message")) {
			gConfig.set("Control.LUR.OpenRegistration.Message","Welcome to the test network.  Your IMSI is ");
		}
		Regexp rxp(gConfig.getStr("Control.LUR.OpenRegistration").c_str());
		openRegistration = rxp.match(IMSI);
		if (gConfig.defines("Control.LUR.OpenRegistration.Reject")) {
			Regexp rxpReject(gConfig.getStr("Control.LUR.OpenRegistration.Reject").c_str());
			bool openRegistrationReject = rxpReject.match(IMSI);
			openRegistration = openRegistration && !openRegistrationReject;
		}
	}

	// Query for IMEI?
	if (gConfig.defines("Control.LUR.QueryIMEI")) {
		DCCH->send(L3IdentityRequest(IMEIType));
		L3Message* msg = getMessage(DCCH);
		L3IdentityResponse *resp = dynamic_cast<L3IdentityResponse*>(msg);
		if (!resp) {
			if (msg) {
				LOG(WARNING) << "Unexpected message " << *msg;
				delete msg;
			}
			throw UnexpectedMessage();
		}
		LOG(INFO) << *resp;
		string new_imei = resp->mobileID().digits();
		if (!gTMSITable.IMEI(IMSI,new_imei.c_str())){
			LOG(WARNING) << "failed access to TMSITable";
		}

		//query subscriber registry for old imei, update if neccessary
		string name = string("IMSI") + IMSI;
		string old_imei = gSubscriberRegistry.imsiGet(name, "hardware");

		//if we have a new imei and either there's no old one, or it is different...
		if (!new_imei.empty() && (old_imei.empty() || old_imei != new_imei)){
			LOG(INFO) << "Updating IMSI" << IMSI << " to IMEI:" << new_imei;
			if (gSubscriberRegistry.imsiSet(name,"RRLPSupported", "1")) {
			 	LOG(INFO) << "SR RRLPSupported update problem";
			}
			if (gSubscriberRegistry.imsiSet(name,"hardware", new_imei)) {
				LOG(INFO) << "SR hardware update problem";
			}
		}
		delete msg;
	}

	// Query for classmark?
	if (IMSIAttach && gConfig.defines("Control.LUR.QueryClassmark")) {
		DCCH->send(L3ClassmarkEnquiry());
		L3Message* msg = getMessage(DCCH);
		L3ClassmarkChange *resp = dynamic_cast<L3ClassmarkChange*>(msg);
		if (!resp) {
			if (msg) {
				LOG(WARNING) << "Unexpected message " << *msg;
				delete msg;
			}
			throw UnexpectedMessage();
		}
		LOG(INFO) << *resp;
		const L3MobileStationClassmark2& classmark = resp->classmark();
		if (!gTMSITable.classmark(IMSI,classmark))
			LOG(WARNING) << "failed access to TMSITable";
		delete msg;
	}

	// We fail closed unless we're configured otherwise
	if (!success && !openRegistration) {
		LOG(INFO) << "registration FAILED: " << mobileID;
		DCCH->send(L3LocationUpdatingReject(gConfig.getNum("Control.LUR.UnprovisionedRejectCause")));
		if (!preexistingTMSI) {
			sendWelcomeMessage( "Control.LUR.FailedRegistration.Message",
				"Control.LUR.FailedRegistration.ShortCode", IMSI,DCCH);
		}
		// Release the channel and return.
		DCCH->send(L3ChannelRelease());
		return;
	}

	// If success is true, we had a normal registration.
	// Otherwise, we are here because of open registration.
	// Either way, we're going to register a phone if we arrive here.

	if (success) {
		LOG(INFO) << "registration SUCCESS: " << mobileID;
	} else {
		LOG(INFO) << "registration ALLOWED: " << mobileID;
	}

	// Send the "short name" and time-of-day.
	if (IMSIAttach && gConfig.defines("GSM.Identity.ShortName")) {
		DCCH->send(L3MMInformation(gConfig.getStr("GSM.Identity.ShortName").c_str()));
	}
	// Accept. Make a TMSI assignment, too, if needed.
	if (preexistingTMSI || !gConfig.defines("Control.LUR.SendTMSIs")) {
		DCCH->send(L3LocationUpdatingAccept(gBTS.LAI()));
	} else {
		assert(newTMSI);
		DCCH->send(L3LocationUpdatingAccept(gBTS.LAI(),newTMSI));
		// Wait for MM TMSI REALLOCATION COMPLETE (0x055b).
		L3Frame* resp = DCCH->recv(1000);
		// FIXME -- Actually check the response type.
		if (!resp) {
			LOG(NOTICE) << "no response to TMSI assignment";
		} else {
			LOG(INFO) << *resp;
		}
		delete resp;
	}

	if (gConfig.defines("Control.LUR.QueryRRLP")) {
		// Query for RRLP
		if (!sendRRLP(mobileID, DCCH)) {
			LOG(INFO) << "RRLP request failed";
		}
	}

	// If this is an IMSI attach, send a welcome message.
	if (IMSIAttach) {
		if (success) {
			sendWelcomeMessage( "Control.LUR.NormalRegistration.Message",
				"Control.LUR.NormalRegistration.ShortCode", IMSI, DCCH);
		} else {
			sendWelcomeMessage( "Control.LUR.OpenRegistration.Message",
				"Control.LUR.OpenRegistration.ShortCode", IMSI, DCCH);
		}
	}

	// Release the channel and return.
	DCCH->send(L3ChannelRelease());
	return;
}

// vim: ts=4 sw=4
<|endoftext|>


<commit_before>#include "Run.h"
#include "InputContainer.h"

Run::Run(std::string iTag) : mRunName(iTag) {
   Options runOptions = loadRunOptions(iTag);
   init(runOptions);
}
Run::Run(const Options& iOptions) {
   init(iOptions);
}
void Run::init(const Options& iOptions) {
   mRunOptions = iOptions;

   // Create input service
   mInputContainer = new InputContainer(Options(""));

   // Create a default data object
   // Each configuration needs its own data object, since a configuration can choose its own
   // input sources, downscaler, etc. However we to reuse the downscaler, etc for those
   // configurations that do not need customization. Therefore create a default data object that can
   // reused if needed.
   Options dataOptions0;
   dataOptions0.addOption("runName", mRunName);
   Options::copyOption("inputs", mRunOptions, dataOptions0);
   Options::copyOption("qcs",    mRunOptions, dataOptions0);
   if(!dataOptions0.hasValue("inputs")) {
      std::stringstream ss;
      ss << "Cannot initialize data object. 'inputs' option not provided for run '"
         << mRunName << "'";
      Global::logger->write(ss.str(), Logger::error);
   }
   mDefaultData = new Data(dataOptions0, mInputContainer);

   // Get variable/configurations
   std::map<std::string, std::vector<std::string> > varConfs;
   std::map<std::string, std::vector<std::string> > varMetrics;
   loadVarConfs(mRunOptions, varConfs, varMetrics, mVariables);

   // Loop over all variables
   for(int v = 0; v < mVariables.size(); v++) {
      std::string variable = mVariables[v];

      // Loop over all configurations
      std::vector<std::string> configurations = varConfs[variable];
      for(int c = 0; c < configurations.size(); c++) {
         // Set up options for configuration
         Options configOptions;
         Configuration::getOptions(configurations[c], configOptions);

         ////////////////////////////////////////
         // Pass run options to configurations //
         ////////////////////////////////////////
         Options::copyOption("offsets", mRunOptions, configOptions); // This is needed by the parameter estimation
         if(!configOptions.hasValue("parameterIo")) {
            Options::copyOption("parameterIo", mRunOptions, configOptions);
         }
         if(!configOptions.hasValue("inputs")) {
            Options::copyOption("inputs", mRunOptions, configOptions);
         }
         if(!configOptions.hasValue("numOffsetsSpreadObs")) {
            Options::copyOption("numOffsetsSpreadObs", mRunOptions, configOptions);
         }
         Options::copyOption("numDaysParameterSearch", mRunOptions, configOptions);
         if(!configOptions.hasValue("region")) {
            // Set up how to choose which obs to use in parameter estimation
            Options::copyOption("region", mRunOptions, configOptions);
         }
         // Pass down which output offsets we are producing for
         Options::copyOption("offsets", mRunOptions, configOptions);

         ////////////////////////////////////////
         // Create data for this configuration //
         ////////////////////////////////////////
         Data* data;
         if(configOptions.hasValue("inputs") || configOptions.hasValue("qcs") || configOptions.hasValue("downscaler")) {
            // Create custom data object. NOTE: If any of options are cutomized by configuration,
            // then the downscaler and qcs cannot be reused, since their cached values
            // may be incorrect

            // Initialize with default, then overwrite
            Options dataOptions = dataOptions0;
            dataOptions.addOption("runName", mRunName);
            Options::copyOption("inputs", configOptions, dataOptions);
            // Only copy if it is there
            Options::copyOption("qcs",    configOptions, dataOptions);
            if(!dataOptions.hasValue("inputs")) {
               std::stringstream ss;
               ss << "Cannot initialize data object. 'inputs' neither provided for run '"
                  << mRunName << "' nor for configuration '"
                  << configurations[c] << "'.";
               Global::logger->write(ss.str(), Logger::error);
            }
            data = new Data(dataOptions, mInputContainer);
            mConfigDatas.push_back(data);
         }
         else {
            // No need to create a custom data object, use the default one
            data = mDefaultData;
         }
         Configuration* conf = Configuration::getScheme(configOptions, *data);
         mVarConfs[variable].push_back(conf);
      }

      // Metrics
      std::vector<std::string> metrics = varMetrics[variable];
      for(int m = 0; m < metrics.size(); m++) {
         Metric* metric = Metric::getScheme(metrics[m], *mDefaultData);
         mMetrics[variable].push_back(metric);
      }
   }

   // Outputs
   std::vector<std::string> outputsString;
   mRunOptions.getValues("outputs", outputsString);
   for(int i = 0; i < outputsString.size(); i++) {
      Output* output = Output::getScheme(outputsString[i], *mDefaultData);
      mOutputs.push_back(output);
   }

   // Debug
   int debug;
   if(!mRunOptions.getValue("debug", debug)) {
      debug = 0;
   }
   Global::logger->setMaxLevel((Logger::Level) debug);

   //////////////
   // Location //
   //////////////
   std::string locationSetTag;
   if(mRunOptions.getValue("locationTag", locationSetTag)) {
      Input* input = mInputContainer->getInput(locationSetTag);
      mLocations = input->getLocations();
      delete input;
   }
   else {
      // Assume that we want to forecast for locations where have obs
      Input* input = mDefaultData->getObsInput();
      if(input != NULL) {
         mLocations = input->getLocations();
      }
   }
   if(mLocations.size() == 0) {
      std::stringstream ss;
      ss << "Run: No locations to produce forecasts for are defined for run '"
         << mRunName << "'. Either add an observation dataset to the run's 'inputs' option, "
         << "or use the 'locationTag' option to specify which dataset to use locations from.";
      Global::logger->write(ss.str(), Logger::error);
   }
   std::vector<int> useLocations;
   if(mRunOptions.getValues("locations", useLocations)) {
      std::vector<Location> temp = mLocations;
      mLocations.clear();
      for(int k = 0; k < (int) temp.size(); k++) {
         for(int i = 0; i < (int) useLocations.size(); i++) {
            if(temp[k].getId() == useLocations[i]) {
               mLocations.push_back(temp[k]);
            }
         }
      }
      if(mLocations.size() == 0) {
         std::stringstream ss;
         ss << "No valid locations selected by 'locations' run option";
         Global::logger->write(ss.str(), Logger::error);
      }
   }

   /////////////
   // Offsets //
   /////////////
   if(mRunOptions.getValues("offsets", mOffsets)) {
      std::stringstream ss;
      ss << "Using offsets from run specifications";
      Global::logger->write(ss.str(), Logger::critical);
   }
   else {
      Input* input;
      std::string offsetSetTag;
      if(mRunOptions.getValue("offsetTag", offsetSetTag)) {
         input = mInputContainer->getInput(offsetSetTag);
      }
      else {
         // Default to main forecast set, because ...
         input = mDefaultData->getInput();
      }
      std::stringstream ss;
      ss << "Using offsets from dataset " << input->getName();
      Global::logger->write(ss.str(), Logger::status);
      mOffsets = input->getOffsets();
      delete input;
   }
}

Run::~Run() {
   delete mInputContainer;
   delete mDefaultData;
   for(int i = 0; i < mConfigDatas.size(); i++) {
      delete mConfigDatas[i];
   }
}

Options Run::loadRunOptions(std::string iTag) const {
   int dotPosition = -1;
   for(int i = 0; i < iTag.size(); i++) {
      if(iTag[i] == '.')
         dotPosition = i;
   }
   std::string filename;
   std::string tag;
   if(dotPosition == -1) {
      std::stringstream ss;
      ss << Namelist::getDefaultLocation() << "default/runs.nl";
      filename = ss.str();
      tag = iTag;
   }
   else {
      assert(dotPosition != 0);
      std::string folder = iTag.substr(0,dotPosition);
      tag = iTag.substr(dotPosition+1);//, iTag.size()-2);
      std::stringstream ss;
      ss << Namelist::getDefaultLocation() << folder << "/runs" << ".nl";
      filename = ss.str();
   }
   Namelist nlRuns(filename);
   std::string optString = nlRuns.findLine(tag);
   if(optString == "") {
      std::stringstream ss;
      ss << "Run " << iTag << " does not exist";
      Global::logger->write(ss.str(), Logger::error);
   }
   return Options(optString);
}

void Run::loadVarConfs(const Options& iRunOptions,
      std::map<std::string, std::vector<std::string> >& iVarConfs,
      std::map<std::string, std::vector<std::string> >& iMetrics,
      std::vector<std::string>& iVariables) const {
   // Variable-configurations
   std::vector<std::string> varConfs;
   std::set<std::string> variables;
   iRunOptions.getValues("varconfs", varConfs);
   if(varConfs.size() == 0) {
      Global::logger->write("No variable/configurations specified for this run", Logger::error);
   }
   for(int v = 0; v < (int) varConfs.size(); v++) {
      std::string currVarConf = varConfs[v];
      // Read from file
      int dotPosition = -1;
      for(int i = 0; i < currVarConf.size(); i++) {
         if(currVarConf[i] == '.')
            dotPosition = i;
      }
      std::string folder;
      std::string tag;
      if(dotPosition == -1) {
         folder = "default";
         tag = currVarConf;
      }
      else {
         assert(dotPosition != 0);
         folder = currVarConf.substr(0,dotPosition);
         tag = currVarConf.substr(dotPosition+1);//, iTag.size()-2);
      }
      Namelist nlVarConfs("varconfs", folder);

      std::string line = nlVarConfs.findLine(tag);
      if(line == "") {
         std::stringstream ss;
         ss << "Variable/Configuration '" << tag << "' does not exist";
         Global::logger->write(ss.str(), Logger::error);
      }
      Options opt(line);
      // Variable
      std::string variable;
      opt.getRequiredValue("variable", variable);
      variables.insert(variable);

      // Configuration
      std::vector<std::string> configurations;
      opt.getRequiredValues("configurations", configurations);
      for(int i = 0; i < configurations.size(); i++)
         iVarConfs[variable].push_back(configurations[i]);

      // Set up metrics
      std::vector<std::string> metricTags;
      opt.getValues("metrics", metricTags);
      for(int i = 0; i < metricTags.size(); i++)
         iMetrics[variable].push_back(metricTags[i]);
   }
   iVariables = std::vector<std::string>(variables.begin(), variables.end());
}
void Run::getRunOptions(Options& iOptions) const {
   iOptions = mRunOptions;
}

std::vector<Output*> Run::getOutputs() const {
   return mOutputs;
}

Data* Run::getData() const {
   return mDefaultData;
}
std::vector<Location> Run::getLocations() const {
   return mLocations;
}
std::vector<float> Run::getOffsets() const {
   return mOffsets;
}
std::vector<std::string> Run::getVariables() const {
   return mVariables;
}
std::vector<Configuration*> Run::getConfigurations(const std::string& iVariable) const {
   std::vector<Configuration*> configurations;
   std::map<std::string, std::vector<Configuration*> >::const_iterator it = mVarConfs.find(iVariable);
   if(it == mVarConfs.end()) {
      std::stringstream ss;
      ss << "Run: No configuration specified for variable " << iVariable;
      Global::logger->write(ss.str(), Logger::debug);
   }
   else {
      configurations =  it->second;
   }
   return configurations;
}

std::vector<Configuration*> Run::getConfigurations() const {
   std::vector<Configuration*> configurations;
   std::map<std::string, std::vector<Configuration*> >::const_iterator it;
   for(it = mVarConfs.begin(); it != mVarConfs.end(); it++) {
      for(int i = 0; i < it->second.size(); i++) {
         configurations.push_back(it->second[i]);
      }
   }
   return configurations;
}

std::vector<Metric*> Run::getMetrics(const std::string& iVariable) const {
   std::vector<Metric*> metrics;
   std::map<std::string, std::vector<Metric*> >::const_iterator it = mMetrics.find(iVariable);
   if(it == mMetrics.end()) {
      std::stringstream ss;
      ss << "Run: No metrics specified for variable " << iVariable;
      Global::logger->write(ss.str(), Logger::debug);
   }
   else {
      metrics = it->second;
   }
   return metrics;
}
<commit_msg>Fixes bug where the Run accidentally deletes inputs<commit_after>#include "Run.h"
#include "InputContainer.h"

Run::Run(std::string iTag) : mRunName(iTag) {
   Options runOptions = loadRunOptions(iTag);
   init(runOptions);
}
Run::Run(const Options& iOptions) {
   init(iOptions);
}
void Run::init(const Options& iOptions) {
   mRunOptions = iOptions;

   // Create input service
   mInputContainer = new InputContainer(Options(""));

   // Create a default data object
   // Each configuration needs its own data object, since a configuration can choose its own
   // input sources, downscaler, etc. However we to reuse the downscaler, etc for those
   // configurations that do not need customization. Therefore create a default data object that can
   // reused if needed.
   Options dataOptions0;
   dataOptions0.addOption("runName", mRunName);
   Options::copyOption("inputs", mRunOptions, dataOptions0);
   Options::copyOption("qcs",    mRunOptions, dataOptions0);
   if(!dataOptions0.hasValue("inputs")) {
      std::stringstream ss;
      ss << "Cannot initialize data object. 'inputs' option not provided for run '"
         << mRunName << "'";
      Global::logger->write(ss.str(), Logger::error);
   }
   mDefaultData = new Data(dataOptions0, mInputContainer);

   // Get variable/configurations
   std::map<std::string, std::vector<std::string> > varConfs;
   std::map<std::string, std::vector<std::string> > varMetrics;
   loadVarConfs(mRunOptions, varConfs, varMetrics, mVariables);

   // Loop over all variables
   for(int v = 0; v < mVariables.size(); v++) {
      std::string variable = mVariables[v];

      // Loop over all configurations
      std::vector<std::string> configurations = varConfs[variable];
      for(int c = 0; c < configurations.size(); c++) {
         // Set up options for configuration
         Options configOptions;
         Configuration::getOptions(configurations[c], configOptions);

         ////////////////////////////////////////
         // Pass run options to configurations //
         ////////////////////////////////////////
         Options::copyOption("offsets", mRunOptions, configOptions); // This is needed by the parameter estimation
         if(!configOptions.hasValue("parameterIo")) {
            Options::copyOption("parameterIo", mRunOptions, configOptions);
         }
         if(!configOptions.hasValue("inputs")) {
            Options::copyOption("inputs", mRunOptions, configOptions);
         }
         if(!configOptions.hasValue("numOffsetsSpreadObs")) {
            Options::copyOption("numOffsetsSpreadObs", mRunOptions, configOptions);
         }
         Options::copyOption("numDaysParameterSearch", mRunOptions, configOptions);
         if(!configOptions.hasValue("region")) {
            // Set up how to choose which obs to use in parameter estimation
            Options::copyOption("region", mRunOptions, configOptions);
         }
         // Pass down which output offsets we are producing for
         Options::copyOption("offsets", mRunOptions, configOptions);

         ////////////////////////////////////////
         // Create data for this configuration //
         ////////////////////////////////////////
         Data* data;
         if(configOptions.hasValue("inputs") || configOptions.hasValue("qcs") || configOptions.hasValue("downscaler")) {
            // Create custom data object. NOTE: If any of options are cutomized by configuration,
            // then the downscaler and qcs cannot be reused, since their cached values
            // may be incorrect

            // Initialize with default, then overwrite
            Options dataOptions = dataOptions0;
            dataOptions.addOption("runName", mRunName);
            Options::copyOption("inputs", configOptions, dataOptions);
            // Only copy if it is there
            Options::copyOption("qcs",    configOptions, dataOptions);
            if(!dataOptions.hasValue("inputs")) {
               std::stringstream ss;
               ss << "Cannot initialize data object. 'inputs' neither provided for run '"
                  << mRunName << "' nor for configuration '"
                  << configurations[c] << "'.";
               Global::logger->write(ss.str(), Logger::error);
            }
            data = new Data(dataOptions, mInputContainer);
            mConfigDatas.push_back(data);
         }
         else {
            // No need to create a custom data object, use the default one
            data = mDefaultData;
         }
         Configuration* conf = Configuration::getScheme(configOptions, *data);
         mVarConfs[variable].push_back(conf);
      }

      // Metrics
      std::vector<std::string> metrics = varMetrics[variable];
      for(int m = 0; m < metrics.size(); m++) {
         Metric* metric = Metric::getScheme(metrics[m], *mDefaultData);
         mMetrics[variable].push_back(metric);
      }
   }

   // Outputs
   std::vector<std::string> outputsString;
   mRunOptions.getValues("outputs", outputsString);
   for(int i = 0; i < outputsString.size(); i++) {
      Output* output = Output::getScheme(outputsString[i], *mDefaultData);
      mOutputs.push_back(output);
   }

   // Debug
   int debug;
   if(!mRunOptions.getValue("debug", debug)) {
      debug = 0;
   }
   Global::logger->setMaxLevel((Logger::Level) debug);

   //////////////
   // Location //
   //////////////
   std::string locationSetTag;
   if(mRunOptions.getValue("locationTag", locationSetTag)) {
      Input* input = mInputContainer->getInput(locationSetTag);
      mLocations = input->getLocations();
   }
   else {
      // Assume that we want to forecast for locations where have obs
      Input* input = mDefaultData->getObsInput();
      if(input != NULL) {
         mLocations = input->getLocations();
      }
   }
   if(mLocations.size() == 0) {
      std::stringstream ss;
      ss << "Run: No locations to produce forecasts for are defined for run '"
         << mRunName << "'. Either add an observation dataset to the run's 'inputs' option, "
         << "or use the 'locationTag' option to specify which dataset to use locations from.";
      Global::logger->write(ss.str(), Logger::error);
   }
   std::vector<int> useLocations;
   if(mRunOptions.getValues("locations", useLocations)) {
      std::vector<Location> temp = mLocations;
      mLocations.clear();
      for(int k = 0; k < (int) temp.size(); k++) {
         for(int i = 0; i < (int) useLocations.size(); i++) {
            if(temp[k].getId() == useLocations[i]) {
               mLocations.push_back(temp[k]);
            }
         }
      }
      if(mLocations.size() == 0) {
         std::stringstream ss;
         ss << "No valid locations selected by 'locations' run option";
         Global::logger->write(ss.str(), Logger::error);
      }
   }

   /////////////
   // Offsets //
   /////////////
   if(mRunOptions.getValues("offsets", mOffsets)) {
      std::stringstream ss;
      ss << "Using offsets from run specifications";
      Global::logger->write(ss.str(), Logger::critical);
   }
   else {
      Input* input;
      std::string offsetSetTag;
      if(mRunOptions.getValue("offsetTag", offsetSetTag)) {
         input = mInputContainer->getInput(offsetSetTag);
      }
      else {
         // Default to main forecast set, because ...
         input = mDefaultData->getInput();
      }
      std::stringstream ss;
      ss << "Using offsets from dataset " << input->getName();
      Global::logger->write(ss.str(), Logger::status);
      mOffsets = input->getOffsets();
   }
}

Run::~Run() {
   delete mInputContainer;
   delete mDefaultData;
   for(int i = 0; i < mConfigDatas.size(); i++) {
      delete mConfigDatas[i];
   }
}

Options Run::loadRunOptions(std::string iTag) const {
   int dotPosition = -1;
   for(int i = 0; i < iTag.size(); i++) {
      if(iTag[i] == '.')
         dotPosition = i;
   }
   std::string filename;
   std::string tag;
   if(dotPosition == -1) {
      std::stringstream ss;
      ss << Namelist::getDefaultLocation() << "default/runs.nl";
      filename = ss.str();
      tag = iTag;
   }
   else {
      assert(dotPosition != 0);
      std::string folder = iTag.substr(0,dotPosition);
      tag = iTag.substr(dotPosition+1);//, iTag.size()-2);
      std::stringstream ss;
      ss << Namelist::getDefaultLocation() << folder << "/runs" << ".nl";
      filename = ss.str();
   }
   Namelist nlRuns(filename);
   std::string optString = nlRuns.findLine(tag);
   if(optString == "") {
      std::stringstream ss;
      ss << "Run " << iTag << " does not exist";
      Global::logger->write(ss.str(), Logger::error);
   }
   return Options(optString);
}

void Run::loadVarConfs(const Options& iRunOptions,
      std::map<std::string, std::vector<std::string> >& iVarConfs,
      std::map<std::string, std::vector<std::string> >& iMetrics,
      std::vector<std::string>& iVariables) const {
   // Variable-configurations
   std::vector<std::string> varConfs;
   std::set<std::string> variables;
   iRunOptions.getValues("varconfs", varConfs);
   if(varConfs.size() == 0) {
      Global::logger->write("No variable/configurations specified for this run", Logger::error);
   }
   for(int v = 0; v < (int) varConfs.size(); v++) {
      std::string currVarConf = varConfs[v];
      // Read from file
      int dotPosition = -1;
      for(int i = 0; i < currVarConf.size(); i++) {
         if(currVarConf[i] == '.')
            dotPosition = i;
      }
      std::string folder;
      std::string tag;
      if(dotPosition == -1) {
         folder = "default";
         tag = currVarConf;
      }
      else {
         assert(dotPosition != 0);
         folder = currVarConf.substr(0,dotPosition);
         tag = currVarConf.substr(dotPosition+1);//, iTag.size()-2);
      }
      Namelist nlVarConfs("varconfs", folder);

      std::string line = nlVarConfs.findLine(tag);
      if(line == "") {
         std::stringstream ss;
         ss << "Variable/Configuration '" << tag << "' does not exist";
         Global::logger->write(ss.str(), Logger::error);
      }
      Options opt(line);
      // Variable
      std::string variable;
      opt.getRequiredValue("variable", variable);
      variables.insert(variable);

      // Configuration
      std::vector<std::string> configurations;
      opt.getRequiredValues("configurations", configurations);
      for(int i = 0; i < configurations.size(); i++)
         iVarConfs[variable].push_back(configurations[i]);

      // Set up metrics
      std::vector<std::string> metricTags;
      opt.getValues("metrics", metricTags);
      for(int i = 0; i < metricTags.size(); i++)
         iMetrics[variable].push_back(metricTags[i]);
   }
   iVariables = std::vector<std::string>(variables.begin(), variables.end());
}
void Run::getRunOptions(Options& iOptions) const {
   iOptions = mRunOptions;
}

std::vector<Output*> Run::getOutputs() const {
   return mOutputs;
}

Data* Run::getData() const {
   return mDefaultData;
}
std::vector<Location> Run::getLocations() const {
   return mLocations;
}
std::vector<float> Run::getOffsets() const {
   return mOffsets;
}
std::vector<std::string> Run::getVariables() const {
   return mVariables;
}
std::vector<Configuration*> Run::getConfigurations(const std::string& iVariable) const {
   std::vector<Configuration*> configurations;
   std::map<std::string, std::vector<Configuration*> >::const_iterator it = mVarConfs.find(iVariable);
   if(it == mVarConfs.end()) {
      std::stringstream ss;
      ss << "Run: No configuration specified for variable " << iVariable;
      Global::logger->write(ss.str(), Logger::debug);
   }
   else {
      configurations =  it->second;
   }
   return configurations;
}

std::vector<Configuration*> Run::getConfigurations() const {
   std::vector<Configuration*> configurations;
   std::map<std::string, std::vector<Configuration*> >::const_iterator it;
   for(it = mVarConfs.begin(); it != mVarConfs.end(); it++) {
      for(int i = 0; i < it->second.size(); i++) {
         configurations.push_back(it->second[i]);
      }
   }
   return configurations;
}

std::vector<Metric*> Run::getMetrics(const std::string& iVariable) const {
   std::vector<Metric*> metrics;
   std::map<std::string, std::vector<Metric*> >::const_iterator it = mMetrics.find(iVariable);
   if(it == mMetrics.end()) {
      std::stringstream ss;
      ss << "Run: No metrics specified for variable " << iVariable;
      Global::logger->write(ss.str(), Logger::debug);
   }
   else {
      metrics = it->second;
   }
   return metrics;
}
<|endoftext|>