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