From 3d0f09b39a8c2ee4aa0d636e28f6b42b1c7edd8d Mon Sep 17 00:00:00 2001
From: de Lavenne Alban <alban.de-lavenne@irstea.fr>
Date: Thu, 20 Mar 2025 11:14:28 +0100
Subject: [PATCH] perf: fortran subroutine for convolution

---
 DESCRIPTION               |  4 ++--
 R/convolution.R           |  3 +--
 src/convolution.f90       | 23 +++++++++++++++++++++++
 src/similarity_module.f90 |  2 +-
 src/transfR.c             | 12 +++++++++++-
 5 files changed, 38 insertions(+), 6 deletions(-)
 create mode 100644 src/convolution.f90

diff --git a/DESCRIPTION b/DESCRIPTION
index 65bac29..07572bf 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -1,8 +1,8 @@
 Package: transfR
 Type: Package
 Title: Transfer of Hydrograph from Gauged to Ungauged Catchments
-Version: 1.1.3
-Date: 2025-03-19
+Version: 1.1.4
+Date: 2025-03-20
 Authors@R: c(
   person("Alban", "de Lavenne", role = c("aut", "cre"), comment = c(ORCID = "0000-0002-9448-3490"), email = "alban.delavenne@inrae.fr"),
   person("Christophe", "Cudennec", role = c("ths"), comment = c(ORCID = "0000-0002-1707-8926"), email = "christophe.cudennec@agrocampus-ouest.fr"),
diff --git a/R/convolution.R b/R/convolution.R
index b69ba4f..c169ecf 100644
--- a/R/convolution.R
+++ b/R/convolution.R
@@ -31,8 +31,7 @@ convolution = function(Rn, ...) UseMethod("convolution")
 #' @export
 convolution.default <- function(Rn, uh, continuous=FALSE, ...){
   Q <- rep(0,length(Rn)+length(uh))
-  for(t in which(Rn>0)) Q[t:(t+length(uh)-1)] <- Rn[t]*uh + Q[t:(t+length(uh)-1)]
-  for(t in which(is.na(Rn))) Q[t:(t+length(uh)-1)] <- NA
+  Q <- .Call("c_convolution", rn=Rn, uh=uh)
   if(continuous){
     Q[1:(length(uh)-1)] <- NA
     return(Q[1:length(Rn)])
diff --git a/src/convolution.f90 b/src/convolution.f90
new file mode 100644
index 0000000..c4a85ba
--- /dev/null
+++ b/src/convolution.f90
@@ -0,0 +1,23 @@
+subroutine convolution(rn, uh, nrn, nuh, q) bind(C, name="convolution")
+  use iso_c_binding, only: c_int, c_double
+  use, intrinsic :: ieee_arithmetic
+  implicit none
+  integer(c_int), value :: nrn, nuh
+  real(c_double), intent(in)  :: rn(nrn) 
+  real(c_double), intent(in)  :: uh(nuh)
+  real(c_double), intent(out) :: q(nrn+nuh)
+  real(c_double) :: nan_val
+  integer :: t
+
+  nan_val = ieee_value(0.0_c_double, ieee_quiet_nan)
+  q = 0.0_c_double
+
+  do t = 1, nrn
+    if (ieee_is_nan(rn(t))) then
+      q(t:t+nuh-1) = nan_val
+    else if (rn(t) > 0.0_c_double) then
+      q(t:t+nuh-1) = q(t:t+nuh-1) + rn(t) * uh(1:nuh)
+    end if
+  end do
+
+end subroutine convolution
diff --git a/src/similarity_module.f90 b/src/similarity_module.f90
index a6b1176..0ca78f7 100644
--- a/src/similarity_module.f90
+++ b/src/similarity_module.f90
@@ -31,7 +31,7 @@ contains
       case(4)
         FUN => invrmse
       case default
-        FUN => invrmse
+        FUN => invkge
     end select
 
   end subroutine set_objective_function
diff --git a/src/transfR.c b/src/transfR.c
index cba56b4..31532fa 100644
--- a/src/transfR.c
+++ b/src/transfR.c
@@ -26,10 +26,20 @@ SEXP c_similarity(SEXP Rn, SEXP crit, SEXP nthreads) {
     return sim_matrix;
 }
 
-/* Registration of native routines for .Call */
+extern void convolution(double *rn, double *uh, int nrn, int nuh, double *q);
+SEXP c_convolution(SEXP rn, SEXP uh) {
+    const int nrn = length(rn);
+    const int nuh = length(uh);
+    SEXP q = PROTECT(allocVector(REALSXP, nrn + nuh));   
+    convolution(REAL(rn), REAL(uh), nrn, nuh, REAL(q));
+    UNPROTECT(1);
+    return q;
+}
+
 static const R_CallMethodDef CallEntries[] = {
     {"c_gdist", (DL_FUNC) &c_gdist, 6},
     {"c_similarity", (DL_FUNC) &c_similarity, 3},
+    {"c_convolution", (DL_FUNC) &c_convolution, 2},
     {NULL, NULL, 0}
 };
 
-- 
GitLab