#ifndef ARITHMETICPATHCV_H #define ARITHMETICPATHCV_H #include "colvarmodule.h" #include #include #include #include namespace ArithmeticPathCV { using std::vector; enum path_sz {S, Z}; template class ArithmeticPathBase { public: ArithmeticPathBase() {} virtual ~ArithmeticPathBase() {} virtual void initialize(size_t p_num_elements, size_t p_total_frames, double p_lambda, const vector& p_element, const vector& p_weights); virtual void updateDistanceToReferenceFrames() = 0; virtual void computeValue(); virtual void computeDerivatives(); virtual void compute(); virtual void reComputeLambda(const vector& rmsd_between_refs); protected: scalar_type lambda; vector weights; size_t num_elements; size_t total_frames; vector< vector > frame_element_distances; scalar_type s; scalar_type z; vector dsdx; vector dzdx; private: // intermediate variables vector s_numerator_frame; vector s_denominator_frame; scalar_type numerator_s; scalar_type denominator_s; scalar_type normalization_factor; }; template void ArithmeticPathBase::initialize(size_t p_num_elements, size_t p_total_frames, double p_lambda, const vector& p_element, const vector& p_weights) { lambda = p_lambda; weights = p_weights; num_elements = p_num_elements; total_frames = p_total_frames; frame_element_distances.resize(total_frames, p_element); for (size_t i_frame = 0; i_frame < frame_element_distances.size(); ++i_frame) { for (size_t j_elem = 0; j_elem < num_elements; ++j_elem) { frame_element_distances[i_frame][j_elem].reset(); } } s = scalar_type(0); z = scalar_type(0); dsdx = p_element; dzdx = p_element; s_numerator_frame.resize(total_frames, scalar_type(0)); s_denominator_frame.resize(total_frames, scalar_type(0)); numerator_s = scalar_type(0); denominator_s = scalar_type(0); normalization_factor = 1.0 / static_cast(total_frames - 1); } template void ArithmeticPathBase::computeValue() { updateDistanceToReferenceFrames(); numerator_s = scalar_type(0); denominator_s = scalar_type(0); for (size_t i_frame = 0; i_frame < frame_element_distances.size(); ++i_frame) { scalar_type exponent_tmp = scalar_type(0); for (size_t j_elem = 0; j_elem < num_elements; ++j_elem) { exponent_tmp += weights[j_elem] * frame_element_distances[i_frame][j_elem] * weights[j_elem] * frame_element_distances[i_frame][j_elem]; } exponent_tmp = exponent_tmp * -1.0 * lambda; // prevent underflow if the argument of cvm::exp is less than -708.4 if (exponent_tmp > -708.4) { exponent_tmp = cvm::exp(exponent_tmp); } else { exponent_tmp = 0; } numerator_s += static_cast(i_frame) * exponent_tmp; denominator_s += exponent_tmp; s_numerator_frame[i_frame] = static_cast(i_frame) * exponent_tmp; s_denominator_frame[i_frame] = exponent_tmp; } s = numerator_s / denominator_s * normalization_factor; z = -1.0 / lambda * cvm::logn(denominator_s); } template void ArithmeticPathBase::compute() { computeValue(); computeDerivatives(); } template void ArithmeticPathBase::computeDerivatives() { for (size_t j_elem = 0; j_elem < num_elements; ++j_elem) { element_type dsdxj_numerator_part1(dsdx[j_elem]); element_type dsdxj_numerator_part2(dsdx[j_elem]); element_type dzdxj_numerator(dsdx[j_elem]); dsdxj_numerator_part1.reset(); dsdxj_numerator_part2.reset(); dzdxj_numerator.reset(); for (size_t i_frame = 0; i_frame < frame_element_distances.size(); ++i_frame) { element_type derivative_tmp = -2.0 * lambda * weights[j_elem] * weights[j_elem] * frame_element_distances[i_frame][j_elem]; dsdxj_numerator_part1 += s_numerator_frame[i_frame] * derivative_tmp; dsdxj_numerator_part2 += s_denominator_frame[i_frame] * derivative_tmp; dzdxj_numerator += s_denominator_frame[i_frame] * derivative_tmp; } dsdxj_numerator_part1 *= denominator_s; dsdxj_numerator_part2 *= numerator_s; if ((dsdxj_numerator_part1 - dsdxj_numerator_part2).norm() < std::numeric_limits::min()) { dsdx[j_elem] = 0; } else { dsdx[j_elem] = (dsdxj_numerator_part1 - dsdxj_numerator_part2) / (denominator_s * denominator_s) * normalization_factor; } dzdx[j_elem] = -1.0 / lambda * dzdxj_numerator / denominator_s; } } template void ArithmeticPathBase::reComputeLambda(const vector& rmsd_between_refs) { scalar_type mean_square_displacements = 0.0; for (size_t i_frame = 1; i_frame < total_frames; ++i_frame) { cvm::log(std::string("Distance between frame ") + cvm::to_str(i_frame) + " and " + cvm::to_str(i_frame + 1) + " is " + cvm::to_str(rmsd_between_refs[i_frame - 1]) + std::string("\n")); mean_square_displacements += rmsd_between_refs[i_frame - 1] * rmsd_between_refs[i_frame - 1]; } mean_square_displacements /= scalar_type(total_frames - 1); lambda = 1.0 / mean_square_displacements; } } #endif // ARITHMETICPATHCV_H