Program Listing for File velocity.h

Return to documentation for file (source/relations/velocity.h)

/*
 * velocity.h Atmospheric Boundary Layer velocity profile relations
 *
 * Author:              Tom Clark  (thclark @ github)
 *
 * Copyright (c) 2013-9 Octue Ltd. All Rights Reserved.
 *
 */

#ifndef ES_FLOW_VELOCITY_H_
#define ES_FLOW_VELOCITY_H_

#include <Eigen/Dense>
#include <Eigen/Core>
#include "profile.h"
#include <iostream>


namespace es {

template <typename T, typename Talf>
T power_law_speed(T const & z, const double u_ref, const double z_ref, Talf const & alpha){
    T z_norm = z / z_ref;
    T speed = pow(z_norm, alpha) * u_ref;
    return speed;
};

// Remove template specialisations from doc (causes duplicate) @cond
Eigen::VectorXd power_law_speed(Eigen::VectorXd const & z, const double u_ref, const double z_ref, const double alpha) {
    Eigen::VectorXd z_norm = z.array() / z_ref;
    Eigen::VectorXd speed = pow(z_norm.array(), alpha) * u_ref;
    return speed;
};
// @endcond


template <typename T>
T most_law_speed(T const & z, const double kappa, const double d, const double z0, const double L){
    std::cout << "MOST Law not implemented yet" << std::endl;
    T speed;
    return speed;
}

// Remove template specialisation from doc (causes duplicate) @cond
Eigen::VectorXd most_law_speed(Eigen::VectorXd const & z, const double kappa, const double d, const double z0, const double L){
    std::cout << "MOST Law not implemented yet" << std::endl;
    Eigen::VectorXd speed;
    return speed;
};
// @endcond


template <typename T_z, typename T_pi_j>
T_z marusic_jones_speed(T_z const & z, T_pi_j const pi_j, const double kappa, const double z_0,
                      const double delta, const double u_inf, const double u_tau){
    T_z eta = (z + z_0) / (delta + z_0);
    T_z eta_cubed = pow(eta, 3.0);
    T_z term1 = log(eta) / kappa;
    T_z term2 = (eta_cubed - 1.0) / (3.0 * kappa);
    T_z term3 = 2.0 * pi_j * (1.0 - pow(eta, 2.0) * 3.0 + eta_cubed * 2.0) / kappa;
    T_z u_deficit = term2 - term1 + term3;
    T_z speed = u_inf - u_deficit * u_tau;
    return speed;
};

// Remove template specialisation from doc (causes duplicate) @cond
template <typename T_pi_j>
Eigen::VectorXd marusic_jones_speed(Eigen::VectorXd const & z, T_pi_j const pi_j, const double kappa, const double z_0,
                             const double delta, const double u_inf, const double u_tau){
    Eigen::VectorXd eta = (z.array() + z_0) / (delta + z_0);
    Eigen::VectorXd eta_cubed = eta.array().cube();
    Eigen::VectorXd term1 = eta.array().log() / kappa;
    Eigen::VectorXd term2 = (eta_cubed.array() - 1.0) / (3.0 * kappa);
    Eigen::VectorXd term3 = 2.0 * pi_j * (1.0 - eta.array().square() * 3.0 + eta_cubed.array() * 2.0) / kappa;
    Eigen::VectorXd u_deficit = term2 - term1 + term3;
    Eigen::VectorXd speed = u_inf - u_deficit.array() * u_tau;
    return speed;
};
//@endcond


template <typename T_z, typename T_param>
T_z coles_wake(T_z const &eta, T_param const &pi_coles, const bool corrected=true){
    T_z wake_param, eta_sqd;
    eta_sqd = pow(eta, 2.0);
    if (corrected) {
        wake_param = 2.0 * eta_sqd * (3.0 - 2.0 * eta)
            - eta_sqd * (1.0 - eta) * (1.0 - 2.0 * eta) / pi_coles;
    } else {
        wake_param = 2.0 * eta_sqd * (3.0 - 2.0 * eta);
    }
    return wake_param;
};

// Remove template specialisation from doc (causes duplicate) @cond
template <typename T_param>
Eigen::VectorXd coles_wake(Eigen::VectorXd const &eta, T_param const &pi_coles, const bool corrected=true){
    Eigen::VectorXd wake_param, eta_sqd;
    eta_sqd = eta.array().pow(2.0);
    if (corrected) {
        wake_param = 2.0 * eta_sqd.array() * (3.0 - 2.0 * eta.array())
            - eta_sqd.array() * (1.0 - eta.array()) * (1.0 - 2.0*eta.array()) / pi_coles;
    } else {
        wake_param = 2.0 * eta_sqd.array() * (3.0 - 2.0 * eta.array());
    }
    return wake_param;
};
//@endcond


// Do not document @cond
/* Template wrapper for std::isinf to kill off problems where ceres::Jet is used (autodifferentiation) instead of
 * a double. Call it is_dbl_inf rather than isinf to avoid accidental use.
 */
bool is_double_inf(double in) {
    return std::isinf(in);
};

template <typename T>
bool is_double_inf(T in) {
    return false;
};
// @endcond


template <typename T_eta, typename T_param>
T_eta deficit(T_eta const &eta, const double kappa, T_param const & pi_coles, const double shear_ratio, const bool lewkowicz=false) {
    T_eta f, ones;
    ones = 1.0;
    f = -1.0 * log(eta)/ kappa;
    if (lewkowicz) {
        f = f + (pi_coles/kappa) * coles_wake(ones, pi_coles)
              - (pi_coles/kappa) * coles_wake(eta, pi_coles);
    } else {
        f = f + (pow(eta, 3.0) - 1.0)/(3.0*kappa)
              + 2.0*pi_coles*(1.0 - 3.0*pow(eta, 2.0) + 2.0*pow(eta, 3.0))/kappa;
    }
    if (is_double_inf(f)) {
        f = shear_ratio;
    };
    return f;
}
// Remove template specialisation from doc (causes duplicate) @cond
template <typename T_param>
Eigen::ArrayXd deficit(const Eigen::ArrayXd &eta, const double kappa, T_param const & pi_coles, const double shear_ratio, const bool lewkowicz=false) {
    Eigen::ArrayXd f;
    Eigen::ArrayXd ones;
    ones.setOnes(eta.size());
    f = -1.0 * log(eta)/ kappa;
    if (lewkowicz) {
        f = f + (pi_coles/kappa) * coles_wake(ones, pi_coles)
            - (pi_coles/kappa) * coles_wake(eta, pi_coles);
    } else {
        f = f + (eta.pow(3.0) - 1.0)/(3.0*kappa)
            + 2.0*pi_coles*(1.0 - 3.0*eta.pow(2.) + 2.0*eta.pow(3.0))/kappa;
    }
    for (int k = 0; k < f.size(); k++) {
        if (std::isinf(f[k])) {
            f(k) = shear_ratio;
        }
    }
    return f;
}
// @endcond


template <typename T_z, typename T_param>
T_z lewkowicz_speed(T_z const & z, T_param const & pi_coles, T_param const & kappa, T_param const & u_inf, T_param const & shear_ratio, T_param const &delta_c) {
    T_z f, speed, eta;
    eta = z / delta_c;
    T_param u_tau = u_inf / shear_ratio;
    T_z term1 = log(eta) / (-1.0*kappa);
    T_z term2 = pi_coles * coles_wake(T_z(1.0), pi_coles, true) / kappa;
    T_z term3 = pi_coles * coles_wake(eta, pi_coles, true) / kappa;
    f = term1 + term2 - term3;
    // TODO why isn't this set directly to shear_ratio?
    if (is_double_inf(f)) {
        f = u_inf / u_tau;
    };
    speed = u_inf - f * u_tau;
    return speed;
};

// Remove template specialisation from doc (causes duplicate) @cond
template <typename T_param>
Eigen::VectorXd lewkowicz_speed(Eigen::VectorXd const & z, T_param const &pi_coles, T_param const &kappa, T_param const &u_inf, T_param const &shear_ratio, T_param const &delta_c=1.0){
    Eigen::VectorXd f, speed, eta;
    eta = z.array() / delta_c;
    T_param u_tau = u_inf/shear_ratio;
    Eigen::VectorXd term1 = eta.array().log() / (-1.0*kappa);
    double term2 = pi_coles * coles_wake(1.0, pi_coles) / kappa;
    Eigen::VectorXd term3 = pi_coles * coles_wake(eta, pi_coles).array() / kappa;
    f = term1.array() + term2 - term3.array();
    for (int k = 0; k < f.size(); k++) {
        if (std::isinf(f[k])) {
            f(k) = u_inf / u_tau;
        }
    }
    speed = u_inf - f.array() * u_tau;
    return speed;
};

template <typename T_param>
Eigen::ArrayXd lewkowicz_speed(Eigen::ArrayXd const & z, T_param const &pi_coles, T_param const &kappa, T_param const &u_inf, T_param const &shear_ratio, T_param const &delta_c=1.0){
    Eigen::ArrayXd f, speed, eta;
    eta = z / delta_c;
    T_param u_tau = u_inf/shear_ratio;
    Eigen::ArrayXd term1 = eta.log() / (-1.0*kappa);
    double term2 = pi_coles * coles_wake(1.0, pi_coles) / kappa;
    Eigen::ArrayXd term3 = pi_coles * coles_wake(eta, pi_coles) / kappa;
    f = term1 + term2 - term3;
    for (int k = 0; k < f.size(); k++) {
        if (std::isinf(f[k])) {
            f(k) = u_inf / u_tau;
        }
    }
    speed = u_inf - f * u_tau;
    return speed;
};
// @endcond


} /* namespace es */


#endif /* ES_FLOW_VELOCITY_H_ */