1 2 /* 3 This file contains routines for interfacing to random number generators. 4 This provides more than just an interface to some system random number 5 generator: 6 7 Numbers can be shuffled for use as random tuples 8 9 Multiple random number generators may be used 10 11 We are still not sure what interface we want here. There should be 12 one to reinitialize and set the seed. 13 */ 14 15 #include <petsc/private/randomimpl.h> /*I "petscsys.h" I*/ 16 #include <petscviewer.h> 17 18 /* Logging support */ 19 PetscClassId PETSC_RANDOM_CLASSID; 20 21 /*@C 22 PetscRandomDestroy - Destroys a context that has been formed by 23 PetscRandomCreate(). 24 25 Collective on PetscRandom 26 27 Input Parameter: 28 . r - the random number generator context 29 30 Level: intermediate 31 32 .seealso: PetscRandomGetValue(), PetscRandomCreate(), VecSetRandom() 33 @*/ 34 PetscErrorCode PetscRandomDestroy(PetscRandom *r) 35 { 36 PetscFunctionBegin; 37 if (!*r) PetscFunctionReturn(0); 38 PetscValidHeaderSpecific(*r,PETSC_RANDOM_CLASSID,1); 39 if (--((PetscObject)(*r))->refct > 0) {*r = NULL; PetscFunctionReturn(0);} 40 if ((*r)->ops->destroy) { 41 CHKERRQ((*(*r)->ops->destroy)(*r)); 42 } 43 CHKERRQ(PetscHeaderDestroy(r)); 44 PetscFunctionReturn(0); 45 } 46 47 /*@C 48 PetscRandomGetSeed - Gets the random seed. 49 50 Not collective 51 52 Input Parameters: 53 . r - The random number generator context 54 55 Output Parameter: 56 . seed - The random seed 57 58 Level: intermediate 59 60 .seealso: PetscRandomCreate(), PetscRandomSetSeed(), PetscRandomSeed() 61 @*/ 62 PetscErrorCode PetscRandomGetSeed(PetscRandom r,unsigned long *seed) 63 { 64 PetscFunctionBegin; 65 PetscValidHeaderSpecific(r,PETSC_RANDOM_CLASSID,1); 66 if (seed) { 67 PetscValidPointer(seed,2); 68 *seed = r->seed; 69 } 70 PetscFunctionReturn(0); 71 } 72 73 /*@C 74 PetscRandomSetSeed - Sets the random seed. You MUST call PetscRandomSeed() after this call to have the new seed used. 75 76 Not collective 77 78 Input Parameters: 79 + r - The random number generator context 80 - seed - The random seed 81 82 Level: intermediate 83 84 Usage: 85 PetscRandomSetSeed(r,a positive integer); 86 PetscRandomSeed(r); PetscRandomGetValue() will now start with the new seed. 87 88 PetscRandomSeed(r) without a call to PetscRandomSetSeed() re-initializes 89 the seed. The random numbers generated will be the same as before. 90 91 .seealso: PetscRandomCreate(), PetscRandomGetSeed(), PetscRandomSeed() 92 @*/ 93 PetscErrorCode PetscRandomSetSeed(PetscRandom r,unsigned long seed) 94 { 95 PetscFunctionBegin; 96 PetscValidHeaderSpecific(r,PETSC_RANDOM_CLASSID,1); 97 r->seed = seed; 98 CHKERRQ(PetscInfo(NULL,"Setting seed to %d\n",(int)seed)); 99 PetscFunctionReturn(0); 100 } 101 102 /* ------------------------------------------------------------------- */ 103 /* 104 PetscRandomSetTypeFromOptions_Private - Sets the type of random generator from user options. Defaults to type PETSCRAND48 or PETSCRAND. 105 106 Collective on PetscRandom 107 108 Input Parameter: 109 . rnd - The random number generator context 110 111 Level: intermediate 112 113 .seealso: PetscRandomSetFromOptions(), PetscRandomSetType() 114 */ 115 static PetscErrorCode PetscRandomSetTypeFromOptions_Private(PetscOptionItems *PetscOptionsObject,PetscRandom rnd) 116 { 117 PetscBool opt; 118 const char *defaultType; 119 char typeName[256]; 120 121 PetscFunctionBegin; 122 if (((PetscObject)rnd)->type_name) { 123 defaultType = ((PetscObject)rnd)->type_name; 124 } else { 125 defaultType = PETSCRANDER48; 126 } 127 128 CHKERRQ(PetscRandomRegisterAll()); 129 CHKERRQ(PetscOptionsFList("-random_type","PetscRandom type","PetscRandomSetType",PetscRandomList,defaultType,typeName,256,&opt)); 130 if (opt) { 131 CHKERRQ(PetscRandomSetType(rnd, typeName)); 132 } else { 133 CHKERRQ(PetscRandomSetType(rnd, defaultType)); 134 } 135 PetscFunctionReturn(0); 136 } 137 138 /*@ 139 PetscRandomSetFromOptions - Configures the random number generator from the options database. 140 141 Collective on PetscRandom 142 143 Input Parameter: 144 . rnd - The random number generator context 145 146 Options Database: 147 + -random_seed <integer> - provide a seed to the random number generater 148 - -random_no_imaginary_part - makes the imaginary part of the random number zero, this is useful when you want the 149 same code to produce the same result when run with real numbers or complex numbers for regression testing purposes 150 151 Notes: 152 To see all options, run your program with the -help option. 153 Must be called after PetscRandomCreate() but before the rnd is used. 154 155 Level: beginner 156 157 .seealso: PetscRandomCreate(), PetscRandomSetType() 158 @*/ 159 PetscErrorCode PetscRandomSetFromOptions(PetscRandom rnd) 160 { 161 PetscErrorCode ierr; 162 PetscBool set,noimaginary = PETSC_FALSE; 163 PetscInt seed; 164 165 PetscFunctionBegin; 166 PetscValidHeaderSpecific(rnd,PETSC_RANDOM_CLASSID,1); 167 168 ierr = PetscObjectOptionsBegin((PetscObject)rnd);CHKERRQ(ierr); 169 170 /* Handle PetscRandom type options */ 171 CHKERRQ(PetscRandomSetTypeFromOptions_Private(PetscOptionsObject,rnd)); 172 173 /* Handle specific random generator's options */ 174 if (rnd->ops->setfromoptions) { 175 CHKERRQ((*rnd->ops->setfromoptions)(PetscOptionsObject,rnd)); 176 } 177 CHKERRQ(PetscOptionsInt("-random_seed","Seed to use to generate random numbers","PetscRandomSetSeed",0,&seed,&set)); 178 if (set) { 179 CHKERRQ(PetscRandomSetSeed(rnd,(unsigned long int)seed)); 180 CHKERRQ(PetscRandomSeed(rnd)); 181 } 182 CHKERRQ(PetscOptionsBool("-random_no_imaginary_part","The imaginary part of the random number will be zero","PetscRandomSetInterval",noimaginary,&noimaginary,&set)); 183 #if defined(PETSC_HAVE_COMPLEX) 184 if (set) { 185 if (noimaginary) { 186 PetscScalar low,high; 187 CHKERRQ(PetscRandomGetInterval(rnd,&low,&high)); 188 low = low - PetscImaginaryPart(low); 189 high = high - PetscImaginaryPart(high); 190 CHKERRQ(PetscRandomSetInterval(rnd,low,high)); 191 } 192 } 193 #endif 194 ierr = PetscOptionsEnd();CHKERRQ(ierr); 195 CHKERRQ(PetscRandomViewFromOptions(rnd,NULL, "-random_view")); 196 PetscFunctionReturn(0); 197 } 198 199 #if defined(PETSC_HAVE_SAWS) 200 #include <petscviewersaws.h> 201 #endif 202 203 /*@C 204 PetscRandomViewFromOptions - View from Options 205 206 Collective on PetscRandom 207 208 Input Parameters: 209 + A - the random number generator context 210 . obj - Optional object 211 - name - command line option 212 213 Level: intermediate 214 .seealso: PetscRandom, PetscRandomView, PetscObjectViewFromOptions(), PetscRandomCreate() 215 @*/ 216 PetscErrorCode PetscRandomViewFromOptions(PetscRandom A,PetscObject obj,const char name[]) 217 { 218 PetscFunctionBegin; 219 PetscValidHeaderSpecific(A,PETSC_RANDOM_CLASSID,1); 220 CHKERRQ(PetscObjectViewFromOptions((PetscObject)A,obj,name)); 221 PetscFunctionReturn(0); 222 } 223 224 /*@C 225 PetscRandomView - Views a random number generator object. 226 227 Collective on PetscRandom 228 229 Input Parameters: 230 + rnd - The random number generator context 231 - viewer - an optional visualization context 232 233 Notes: 234 The available visualization contexts include 235 + PETSC_VIEWER_STDOUT_SELF - standard output (default) 236 - PETSC_VIEWER_STDOUT_WORLD - synchronized standard 237 output where only the first processor opens 238 the file. All other processors send their 239 data to the first processor to print. 240 241 You can change the format the vector is printed using the 242 option PetscViewerPushFormat(). 243 244 Level: beginner 245 246 .seealso: PetscRealView(), PetscScalarView(), PetscIntView() 247 @*/ 248 PetscErrorCode PetscRandomView(PetscRandom rnd,PetscViewer viewer) 249 { 250 PetscBool iascii; 251 #if defined(PETSC_HAVE_SAWS) 252 PetscBool issaws; 253 #endif 254 255 PetscFunctionBegin; 256 PetscValidHeaderSpecific(rnd,PETSC_RANDOM_CLASSID,1); 257 PetscValidType(rnd,1); 258 if (!viewer) { 259 CHKERRQ(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)rnd),&viewer)); 260 } 261 PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2); 262 PetscCheckSameComm(rnd,1,viewer,2); 263 CHKERRQ(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii)); 264 #if defined(PETSC_HAVE_SAWS) 265 CHKERRQ(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERSAWS,&issaws)); 266 #endif 267 if (iascii) { 268 PetscMPIInt rank; 269 CHKERRQ(PetscObjectPrintClassNamePrefixType((PetscObject)rnd,viewer)); 270 CHKERRMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)rnd),&rank)); 271 CHKERRQ(PetscViewerASCIIPushSynchronized(viewer)); 272 CHKERRQ(PetscViewerASCIISynchronizedPrintf(viewer,"[%d] Random type %s, seed %lu\n",rank,((PetscObject)rnd)->type_name,rnd->seed)); 273 CHKERRQ(PetscViewerFlush(viewer)); 274 CHKERRQ(PetscViewerASCIIPopSynchronized(viewer)); 275 #if defined(PETSC_HAVE_SAWS) 276 } else if (issaws) { 277 PetscMPIInt rank; 278 const char *name; 279 280 CHKERRQ(PetscObjectGetName((PetscObject)rnd,&name)); 281 CHKERRMPI(MPI_Comm_rank(PETSC_COMM_WORLD,&rank)); 282 if (!((PetscObject)rnd)->amsmem && rank == 0) { 283 char dir[1024]; 284 285 CHKERRQ(PetscObjectViewSAWs((PetscObject)rnd,viewer)); 286 CHKERRQ(PetscSNPrintf(dir,1024,"/PETSc/Objects/%s/Low",name)); 287 PetscStackCallSAWs(SAWs_Register,(dir,&rnd->low,1,SAWs_READ,SAWs_DOUBLE)); 288 } 289 #endif 290 } 291 PetscFunctionReturn(0); 292 } 293 294 /*@ 295 PetscRandomCreate - Creates a context for generating random numbers, 296 and initializes the random-number generator. 297 298 Collective 299 300 Input Parameters: 301 . comm - MPI communicator 302 303 Output Parameter: 304 . r - the random number generator context 305 306 Level: intermediate 307 308 Notes: 309 The random type has to be set by PetscRandomSetType(). 310 311 This is only a primative "parallel" random number generator, it should NOT 312 be used for sophisticated parallel Monte Carlo methods since it will very likely 313 not have the correct statistics across processors. You can provide your own 314 parallel generator using PetscRandomRegister(); 315 316 If you create a PetscRandom() using PETSC_COMM_SELF on several processors then 317 the SAME random numbers will be generated on all those processors. Use PETSC_COMM_WORLD 318 or the appropriate parallel communicator to eliminate this issue. 319 320 Use VecSetRandom() to set the elements of a vector to random numbers. 321 322 Example of Usage: 323 .vb 324 PetscRandomCreate(PETSC_COMM_SELF,&r); 325 PetscRandomSetType(r,PETSCRAND48); 326 PetscRandomGetValue(r,&value1); 327 PetscRandomGetValueReal(r,&value2); 328 PetscRandomDestroy(&r); 329 .ve 330 331 .seealso: PetscRandomSetType(), PetscRandomGetValue(), PetscRandomGetValueReal(), PetscRandomSetInterval(), 332 PetscRandomDestroy(), VecSetRandom(), PetscRandomType 333 @*/ 334 335 PetscErrorCode PetscRandomCreate(MPI_Comm comm,PetscRandom *r) 336 { 337 PetscRandom rr; 338 PetscMPIInt rank; 339 340 PetscFunctionBegin; 341 PetscValidPointer(r,2); 342 *r = NULL; 343 CHKERRQ(PetscRandomInitializePackage()); 344 345 CHKERRQ(PetscHeaderCreate(rr,PETSC_RANDOM_CLASSID,"PetscRandom","Random number generator","Sys",comm,PetscRandomDestroy,PetscRandomView)); 346 347 CHKERRMPI(MPI_Comm_rank(comm,&rank)); 348 349 rr->data = NULL; 350 rr->low = 0.0; 351 rr->width = 1.0; 352 rr->iset = PETSC_FALSE; 353 rr->seed = 0x12345678 + 76543*rank; 354 CHKERRQ(PetscRandomSetType(rr,PETSCRANDER48)); 355 *r = rr; 356 PetscFunctionReturn(0); 357 } 358 359 /*@ 360 PetscRandomSeed - Seed the generator. 361 362 Not collective 363 364 Input Parameters: 365 . r - The random number generator context 366 367 Level: intermediate 368 369 Usage: 370 PetscRandomSetSeed(r,a positive integer); 371 PetscRandomSeed(r); PetscRandomGetValue() will now start with the new seed. 372 373 PetscRandomSeed(r) without a call to PetscRandomSetSeed() re-initializes 374 the seed. The random numbers generated will be the same as before. 375 376 .seealso: PetscRandomCreate(), PetscRandomGetSeed(), PetscRandomSetSeed() 377 @*/ 378 PetscErrorCode PetscRandomSeed(PetscRandom r) 379 { 380 PetscFunctionBegin; 381 PetscValidHeaderSpecific(r,PETSC_RANDOM_CLASSID,1); 382 PetscValidType(r,1); 383 384 CHKERRQ((*r->ops->seed)(r)); 385 CHKERRQ(PetscObjectStateIncrease((PetscObject)r)); 386 PetscFunctionReturn(0); 387 } 388