Skip to content

Commit

Permalink
Merge pull request #374 from DrylandEcology/feature_no_pcg_for_rSOILWAT2
Browse files Browse the repository at this point in the history
Encapsulate RNG variable in dedicated type

- new type "sw_random_t"
** for rSOILWAT2 defined as "int" (but unused)
** for SOILWAT2 and STEPWAT2 defined as "pcg32_random_t" (as previously)

- "pcg_basic.h" header now only included by "SW_Defines.h" (for typedef) and by "rands.c" (function calls) -- and only if not rSOILWAT2 -> makefile has new target "libr" to build library without pcg (for rSOILWAT2)

- close #373 "rSOILWAT2 does not use PCG for random numbers - remove requirement on its presence"
  • Loading branch information
dschlaep authored Oct 13, 2023
2 parents 12c88aa + 75cfbd4 commit d05beeb
Show file tree
Hide file tree
Showing 11 changed files with 72 additions and 49 deletions.
16 changes: 16 additions & 0 deletions include/SW_Defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
#include <math.h> /* >= C99; for: atan(), isfinite() */
#include "include/generic.h"

#if !defined(RSOILWAT) /* rSOILWAT2 uses R's RNGs */
#include "external/pcg/pcg_basic.h" // see https://github.com/imneme/pcg-c-basic
#endif


#ifdef __cplusplus
extern "C" {
#endif
Expand Down Expand Up @@ -245,6 +250,17 @@ typedef unsigned int TimeInt;
typedef unsigned int LyrIndex;
typedef signed char flag;


/* =================================================== */
/* RNG structs */
/* --------------------------------------------------- */
#if defined(RSOILWAT)
typedef int sw_random_t; /* not used by rSOILWAT2; it uses instead R's RNG */
#else
typedef pcg32_random_t sw_random_t;
#endif


#ifdef __cplusplus
}
#endif
Expand Down
5 changes: 3 additions & 2 deletions include/SW_datastructs.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
#define DATATYPES_H

#include "include/SW_Defines.h"
#include "external/pcg/pcg_basic.h"


// Array-based output:
#if defined(RSOILWAT) || defined(STEPWAT)
Expand All @@ -27,6 +27,7 @@

#define SW_NFILES 23 // For `InFiles`


/* =================================================== */
/* Carbon structs */
/* --------------------------------------------------- */
Expand Down Expand Up @@ -846,7 +847,7 @@ typedef struct {
u_cov[MAX_WEEKS][2], /* mean weekly maximum and minimum temperature in degree Celsius */
v_cov[MAX_WEEKS][2][2]; /* covariance matrix */
int ppt_events; /* number of ppt events generated this year */
pcg32_random_t markov_rng; // used by STEPWAT2
sw_random_t markov_rng; // used by STEPWAT2

} SW_MARKOV;

Expand Down
15 changes: 7 additions & 8 deletions include/rands.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

#include <stdio.h>
#include <float.h>
#include "external/pcg/pcg_basic.h" // see https://github.com/imneme/pcg-c-basic
#include "include/SW_datastructs.h"

#ifdef __cplusplus
Expand All @@ -32,15 +31,15 @@ typedef long RandListType;
void RandSeed(
unsigned long initstate,
unsigned long initseq,
pcg32_random_t* pcg_rng
sw_random_t* pcg_rng
);
double RandUni(pcg32_random_t* pcg_rng);
int RandUniIntRange(const long first, const long last, pcg32_random_t* pcg_rng);
float RandUniFloatRange(const float min, const float max, pcg32_random_t* pcg_rng);
double RandNorm(double mean, double stddev, pcg32_random_t* pcg_rng);
double RandUni(sw_random_t* pcg_rng);
int RandUniIntRange(const long first, const long last, sw_random_t* pcg_rng);
float RandUniFloatRange(const float min, const float max, sw_random_t* pcg_rng);
double RandNorm(double mean, double stddev, sw_random_t* pcg_rng);
void RandUniList(long count, long first, long last, RandListType list[],
pcg32_random_t* pcg_rng, LOG_INFO* LogInfo);
float RandBeta(float aa, float bb, pcg32_random_t* pcg_rng);
sw_random_t* pcg_rng, LOG_INFO* LogInfo);
float RandBeta(float aa, float bb, sw_random_t* pcg_rng);


#ifdef __cplusplus
Expand Down
15 changes: 11 additions & 4 deletions makefile
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ dir_build_test := $(dir_build)/test
#------ OUTPUT NAMES
target := SOILWAT2
lib_sw2 := $(dir_bin)/lib$(target).a
lib_rsw2 := $(dir_bin)/libr$(target).a
bin_sw2 := $(dir_bin)/$(target)

target_test = $(target)_test
Expand Down Expand Up @@ -256,7 +257,7 @@ sources_test := $(wildcard $(dir_test)/*.cc)
objects_test := $(sources_test:$(dir_test)/%.cc=$(dir_build_test)/%.o)


# PCG random generator files
# PCG random generator files (not used by rSOILWAT2)
sources_pcg := $(dir_pcg)/pcg_basic.c
objects_lib_pcg := $(sources_pcg:$(dir_pcg)/%.c=$(dir_build_sw2)/%.o)
objects_test_pcg := $(sources_pcg:$(dir_pcg)/%.c=$(dir_build_test)/%.o)
Expand All @@ -273,16 +274,22 @@ all : $(bin_sw2)

lib : $(lib_sw2)

libr : $(lib_rsw2)

test : $(bin_test)

.PHONY : all lib test
.PHONY : all lib libr test



#--- SOILWAT2 library (utilized by SOILWAT2, rSOILWAT2, and STEPWAT2)
#--- SOILWAT2 library (utilized by SOILWAT2 and STEPWAT2)
$(lib_sw2) : $(objects_lib) $(objects_lib_pcg) | $(dir_bin)
$(AR) -rcs $(lib_sw2) $(objects_lib) $(objects_lib_pcg)

#--- SOILWAT2 library without pcg (utilized by rSOILWAT2)
$(lib_rsw2) : $(objects_lib) | $(dir_bin)
$(AR) -rcs $(lib_sw2) $(objects_lib)


#--- SOILWAT2 stand-alone executable (utilizing SOILWAT2 library)
$(bin_sw2) : $(lib_sw2) $(objects_bin) | $(dir_bin)
Expand Down Expand Up @@ -407,7 +414,7 @@ clean_bin:
.PHONY : clean_build
clean_build:
-@$(RM) -r $(dir_build_sw2)
-@$(RM) -f $(bin_sw2) $(lib_sw2)
-@$(RM) -f $(bin_sw2) $(lib_sw2) $(lib_rsw2)

.PHONY : clean_test
clean_test:
Expand Down
4 changes: 2 additions & 2 deletions src/SW_Markov.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ static void temp_correct_wetdry(RealD *tmax, RealD *tmin, RealD rain,
@return Daily minimum (*tmin) and maximum (*tmax) temperature.
*/
static void mvnorm(RealD *tmax, RealD *tmin, RealD wTmax, RealD wTmin,
RealD wTmax_var, RealD wTmin_var, RealD wT_covar, pcg32_random_t *markov_rng,
RealD wTmax_var, RealD wTmin_var, RealD wT_covar, sw_random_t *markov_rng,
LOG_INFO* LogInfo) {
/* --------------------------------------------------- */
/* This proc is distilled from a much more general function
Expand Down Expand Up @@ -178,7 +178,7 @@ static void mvnorm(RealD *tmax, RealD *tmin, RealD wTmax, RealD wTmin,
// since `mvnorm` is static we cannot do unit tests unless we set it up
// as an externed function pointer
void (*test_mvnorm)(RealD *, RealD *, RealD, RealD, RealD, RealD,
RealD, pcg32_random_t*, LOG_INFO*) = &mvnorm;
RealD, sw_random_t*, LOG_INFO*) = &mvnorm;
#endif


Expand Down
30 changes: 17 additions & 13 deletions src/rands.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,17 @@
#include "include/myMemory.h"
#include "include/filefuncs.h"

#include "external/pcg/pcg_basic.h"


#ifdef RSOILWAT
// R-API requires that we use it's own random number implementation
// see https://cran.r-project.org/doc/manuals/R-exts.html#Writing-portable-packages
// and https://cran.r-project.org/doc/manuals/R-exts.html#Random-numbers
#include <R_ext/Random.h> // for the random number generators
#include <Rmath.h> // for rnorm()

#else
#include "external/pcg/pcg_basic.h"

#endif


Expand Down Expand Up @@ -56,7 +58,7 @@
void RandSeed(
unsigned long initstate,
unsigned long initseq,
pcg32_random_t* pcg_rng
sw_random_t* pcg_rng
) {
// R uses its own random number generators
#ifndef RSOILWAT
Expand All @@ -72,7 +74,9 @@ void RandSeed(

#else
// silence compile warnings [-Wunused-parameter]
if (pcg_rng == NULL && initstate > 1u && initseq > 1u) {}
(void) pcg_rng;
(void) initstate;
(void) initseq;

#endif
}
Expand All @@ -90,7 +94,7 @@ void RandSeed(
@return A pseudo-random number between 0 and 1.
*/
double RandUni(pcg32_random_t* pcg_rng) {
double RandUni(sw_random_t* pcg_rng) {

double res;

Expand All @@ -99,7 +103,7 @@ double RandUni(pcg32_random_t* pcg_rng) {
res = ldexp(pcg32_random_r(pcg_rng), -32);

#else
if (pcg_rng == NULL) {} // silence compile warnings [-Wunused-parameter]
(void) pcg_rng; // silence compile warnings [-Wunused-parameter]

GetRNGstate();
res = unif_rand();
Expand All @@ -121,7 +125,7 @@ double RandUni(pcg32_random_t* pcg_rng) {
\return Random number between the two bounds defined.
*/
int RandUniIntRange(const long first, const long last, pcg32_random_t* pcg_rng) {
int RandUniIntRange(const long first, const long last, sw_random_t* pcg_rng) {
/* History:
Return a randomly selected integer between
first and last, inclusive.
Expand Down Expand Up @@ -158,7 +162,7 @@ int RandUniIntRange(const long first, const long last, pcg32_random_t* pcg_rng)
res = pcg32_boundedrand_r(pcg_rng, r) + f;

#else
if (pcg_rng == NULL) {} // silence compile warnings [-Wunused-parameter]
(void) pcg_rng; // silence compile warnings [-Wunused-parameter]

GetRNGstate();
res = (long) runif(f, l);
Expand All @@ -180,7 +184,7 @@ int RandUniIntRange(const long first, const long last, pcg32_random_t* pcg_rng)
\return Random number between first and last, inclusive.
*/
float RandUniFloatRange(const float min, const float max, pcg32_random_t* pcg_rng) {
float RandUniFloatRange(const float min, const float max, sw_random_t* pcg_rng) {
/* History:
cwb - 12/5/00
Expand Down Expand Up @@ -235,7 +239,7 @@ float RandUniFloatRange(const float min, const float max, pcg32_random_t* pcg_rn
\param[in] LogInfo Holds information dealing with logfile output
*/
void RandUniList(long count, long first, long last, RandListType list[],
pcg32_random_t* pcg_rng, LOG_INFO* LogInfo) {
sw_random_t* pcg_rng, LOG_INFO* LogInfo) {

long i, j, c, range, *klist;

Expand Down Expand Up @@ -318,7 +322,7 @@ void RandUniList(long count, long first, long last, RandListType list[],
\param stddev Standard deviation of the distribution.
\param[in,out] *pcg_rng The random number generator to use.
*/
double RandNorm(double mean, double stddev, pcg32_random_t* pcg_rng) {
double RandNorm(double mean, double stddev, sw_random_t* pcg_rng) {
/* History:
cwb - 6/20/00
This routine is
Expand Down Expand Up @@ -374,7 +378,7 @@ double RandNorm(double mean, double stddev, pcg32_random_t* pcg_rng) {


#else
if (pcg_rng == NULL) {} // silence compile warnings [-Wunused-parameter]
(void) pcg_rng; // silence compile warnings [-Wunused-parameter]

GetRNGstate();
res = rnorm(mean, stddev);
Expand Down Expand Up @@ -408,7 +412,7 @@ double RandNorm(double mean, double stddev, pcg32_random_t* pcg_rng) {
\param[in,out] *pcg_rng The random number generator to use.
\return A random variate of a beta distribution.
*/
float RandBeta ( float aa, float bb, pcg32_random_t* pcg_rng) {
float RandBeta ( float aa, float bb, sw_random_t* pcg_rng) {
float a;
float alpha;
float b;
Expand Down
5 changes: 2 additions & 3 deletions tests/gtests/test_SW_Flow_Lib.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,12 @@
#include "include/SW_Weather.h"
#include "include/SW_Markov.h"
#include "include/SW_Sky.h"
#include "external/pcg/pcg_basic.h"

#include "include/SW_Flow_lib.h"

#include "tests/gtests/sw_testhelpers.h"

pcg32_random_t flow_rng;
sw_random_t flow_rng;
//SW_SOILWAT_OUTPUTS *swo = NULL;

int k;
Expand Down Expand Up @@ -220,7 +219,7 @@ namespace
double *impermeability2 = new double[nlyrs];
double *drain2 = new double[nlyrs];

pcg32_random_t infiltrate_rng;
sw_random_t infiltrate_rng;
RandSeed(0u, 0u, &infiltrate_rng);

for (i = 0; i < MAX_LAYERS; i++)
Expand Down
1 change: 0 additions & 1 deletion tests/gtests/test_SW_Flow_Lib_PET.cc
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
#include "include/SW_Weather.h"
#include "include/SW_Markov.h"
#include "include/SW_Sky.h"
#include "external/pcg/pcg_basic.h"

#include "include/SW_Flow_lib_PET.h"

Expand Down
13 changes: 6 additions & 7 deletions tests/gtests/test_SW_Flow_lib_temp.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,13 @@
#include "include/SW_Weather.h"
#include "include/SW_Markov.h"
#include "include/SW_Sky.h"
#include "external/pcg/pcg_basic.h"

#include "include/SW_Flow_lib.h"

#include "tests/gtests/sw_testhelpers.h"


pcg32_random_t flowTemp_rng;
sw_random_t flowTemp_rng;

namespace {

Expand Down Expand Up @@ -95,7 +94,7 @@ namespace {
double deltaX = 15.0, theMaxDepth = 990.0, sTconst = 4.15;
unsigned int nlyrs, nRgr = 65;
Bool ptr_stError = swFALSE;
pcg32_random_t STInit_rng;
sw_random_t STInit_rng;
RandSeed(0u, 0u, &STInit_rng);

// ***** Test when nlyrs = 1 ***** //
Expand Down Expand Up @@ -181,7 +180,7 @@ namespace {
double *bDensity2 = new double[nlyrs];
double *fc2 = new double[nlyrs];
double *wp2 = new double[nlyrs];
pcg32_random_t STInitDeath_rng;
sw_random_t STInitDeath_rng;
RandSeed(0u, 0u, &STInitDeath_rng);

for (i = 0; i < nlyrs; i++) {
Expand Down Expand Up @@ -221,7 +220,7 @@ namespace {
unsigned int nlyrs, nRgr = 65;
Bool ptr_stError = swFALSE;

pcg32_random_t SLIF_rng;
sw_random_t SLIF_rng;
RandSeed(0u, 0u, &SLIF_rng);

// ***** Test when nlyrs = 1 ***** //
Expand Down Expand Up @@ -377,7 +376,7 @@ namespace {
unsigned int nRgr =65, year = 1980, doy = 1;
Bool ptr_stError = swFALSE;

pcg32_random_t STTF_rng;
sw_random_t STTF_rng;
RandSeed(0u, 0u, &STTF_rng);

// declare input in for loop for non-error causing conditions;
Expand Down Expand Up @@ -614,7 +613,7 @@ namespace {


// ***** Test when nlyrs = MAX_LAYERS ***** //
pcg32_random_t soilTemp_rng;
sw_random_t soilTemp_rng;
RandSeed(0u, 0u, &soilTemp_rng);


Expand Down
2 changes: 1 addition & 1 deletion tests/gtests/test_SW_Markov.cc
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@


extern void (*test_mvnorm)(RealD *, RealD *, RealD, RealD, RealD, RealD, RealD,
pcg32_random_t*, LOG_INFO*);
sw_random_t*, LOG_INFO*);
extern void (*test_temp_correct_wetdry)(RealD *, RealD *, RealD, RealD, RealD, RealD, RealD);


Expand Down
Loading

0 comments on commit d05beeb

Please sign in to comment.