1 #define PETSC_DLL 2 /* 3 Utilites routines to add simple ASCII IO capability. 4 */ 5 #include "src/sys/fileio/mprint.h" 6 #include "petscconfiginfo.h" 7 /* 8 If petsc_history is on, then all Petsc*Printf() results are saved 9 if the appropriate (usually .petschistory) file. 10 */ 11 extern FILE *petsc_history; 12 /* 13 Allows one to overwrite where standard out is sent. For example 14 PETSC_STDOUT = fopen("/dev/ttyXX","w") will cause all standard out 15 writes to go to terminal XX; assuming you have write permission there 16 */ 17 FILE *PETSC_STDOUT = 0; 18 19 #undef __FUNCT__ 20 #define __FUNCT__ "PetscFormatConvert" 21 PetscErrorCode PETSC_DLLEXPORT PetscFormatConvert(const char *format,char *newformat,PetscInt size) 22 { 23 PetscInt i = 0,j = 0; 24 25 while (format[i] && i < size-1) { 26 if (format[i] == '%' && format[i+1] == 'D') { 27 newformat[j++] = '%'; 28 #if defined(PETSC_USE_32BIT_INT) 29 newformat[j++] = 'd'; 30 #else 31 newformat[j++] = 'l'; 32 newformat[j++] = 'l'; 33 newformat[j++] = 'd'; 34 #endif 35 i += 2; 36 } else if (format[i] == '%' && format[i+1] >= '1' && format[i+1] <= '9' && format[i+2] == 'D') { 37 newformat[j++] = '%'; 38 newformat[j++] = format[i+1]; 39 #if defined(PETSC_USE_32BIT_INT) 40 newformat[j++] = 'd'; 41 #else 42 newformat[j++] = 'l'; 43 newformat[j++] = 'l'; 44 newformat[j++] = 'd'; 45 #endif 46 i += 3; 47 } else if (format[i] == '%' && format[i+1] == 'G') { 48 newformat[j++] = '%'; 49 #if defined(PETSC_USE_INT) 50 newformat[j++] = 'd'; 51 #elif !defined(PETSC_USE_LONG_DOUBLE) 52 newformat[j++] = 'g'; 53 #else 54 newformat[j++] = 'L'; 55 newformat[j++] = 'g'; 56 #endif 57 i += 2; 58 }else { 59 newformat[j++] = format[i++]; 60 } 61 } 62 newformat[j] = 0; 63 return 0; 64 } 65 66 #undef __FUNCT__ 67 #define __FUNCT__ "PetscVSNPrintf" 68 /* 69 No error handling because may be called by error handler 70 */ 71 PetscErrorCode PETSC_DLLEXPORT PetscVSNPrintf(char *str,size_t len,const char *format,va_list Argp) 72 { 73 /* no malloc since may be called by error handler */ 74 char newformat[8*1024]; 75 size_t length; 76 PetscErrorCode ierr; 77 78 PetscFormatConvert(format,newformat,8*1024); 79 ierr = PetscStrlen(newformat, &length);CHKERRQ(ierr); 80 if (length > len) { 81 newformat[len] = '\0'; 82 } 83 #if defined(PETSC_HAVE_VPRINTF_CHAR) 84 vsprintf(str,newformat,(char *)Argp); 85 #else 86 vsprintf(str,newformat,Argp); 87 #endif 88 return 0; 89 } 90 91 #undef __FUNCT__ 92 #define __FUNCT__ "PetscVFPrintf" 93 /* 94 All PETSc standard out and error messages are sent through this function; so, in theory, this can 95 can be replaced with something that does not simply write to a file. 96 97 Note: For error messages this may be called by a process, for regular standard out it is 98 called only by process 0 of a given communicator 99 100 No error handling because may be called by error handler 101 */ 102 PetscErrorCode PETSC_DLLEXPORT PetscVFPrintf(FILE *fd,const char *format,va_list Argp) 103 { 104 /* no malloc since may be called by error handler */ 105 char newformat[8*1024]; 106 107 PetscFormatConvert(format,newformat,8*1024); 108 #if defined(PETSC_HAVE_VPRINTF_CHAR) 109 vfprintf(fd,newformat,(char *)Argp); 110 #else 111 vfprintf(fd,newformat,Argp); 112 fflush(fd); 113 #endif 114 return 0; 115 } 116 117 #undef __FUNCT__ 118 #define __FUNCT__ "PetscSNPrintf" 119 /*@C 120 PetscSNPrintf - Prints to a string of given length 121 122 Not Collective 123 124 Input Parameters: 125 + str - the string to print to 126 . len - the length of str 127 . format - the usual printf() format string 128 - any arguments 129 130 Level: intermediate 131 132 .seealso: PetscSynchronizedFlush(), PetscSynchronizedFPrintf(), PetscFPrintf(), PetscVSNPrintf(), 133 PetscPrintf(), PetscViewerASCIIPrintf(), PetscViewerASCIISynchronizedPrintf() 134 @*/ 135 PetscErrorCode PETSC_DLLEXPORT PetscSNPrintf(char *str,size_t len,const char format[],...) 136 { 137 PetscErrorCode ierr; 138 va_list Argp; 139 140 PetscFunctionBegin; 141 va_start(Argp,format); 142 ierr = PetscVSNPrintf(str,len,format,Argp);CHKERRQ(ierr); 143 PetscFunctionReturn(0); 144 } 145 146 /* ----------------------------------------------------------------------- */ 147 148 PrintfQueue queue = 0,queuebase = 0; 149 int queuelength = 0; 150 FILE *queuefile = PETSC_NULL; 151 152 #undef __FUNCT__ 153 #define __FUNCT__ "PetscSynchronizedPrintf" 154 /*@C 155 PetscSynchronizedPrintf - Prints synchronized output from several processors. 156 Output of the first processor is followed by that of the second, etc. 157 158 Not Collective 159 160 Input Parameters: 161 + comm - the communicator 162 - format - the usual printf() format string 163 164 Level: intermediate 165 166 Notes: 167 REQUIRES a intervening call to PetscSynchronizedFlush() for the information 168 from all the processors to be printed. 169 170 Fortran Note: 171 The call sequence is PetscSynchronizedPrintf(PetscViewer, character(*), PetscErrorCode ierr) from Fortran. 172 That is, you can only pass a single character string from Fortran. 173 174 The length of the formatted message cannot exceed QUEUESTRINGSIZE characters. 175 176 .seealso: PetscSynchronizedFlush(), PetscSynchronizedFPrintf(), PetscFPrintf(), 177 PetscPrintf(), PetscViewerASCIIPrintf(), PetscViewerASCIISynchronizedPrintf() 178 @*/ 179 PetscErrorCode PETSC_DLLEXPORT PetscSynchronizedPrintf(MPI_Comm comm,const char format[],...) 180 { 181 PetscErrorCode ierr; 182 PetscMPIInt rank; 183 184 PetscFunctionBegin; 185 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); 186 187 /* First processor prints immediately to stdout */ 188 if (!rank) { 189 va_list Argp; 190 va_start(Argp,format); 191 ierr = PetscVFPrintf(PETSC_STDOUT,format,Argp);CHKERRQ(ierr); 192 if (petsc_history) { 193 ierr = PetscVFPrintf(petsc_history,format,Argp);CHKERRQ(ierr); 194 } 195 va_end(Argp); 196 } else { /* other processors add to local queue */ 197 va_list Argp; 198 PrintfQueue next; 199 200 ierr = PetscNew(struct _PrintfQueue,&next);CHKERRQ(ierr); 201 if (queue) {queue->next = next; queue = next; queue->next = 0;} 202 else {queuebase = queue = next;} 203 queuelength++; 204 va_start(Argp,format); 205 ierr = PetscMemzero(next->string,QUEUESTRINGSIZE);CHKERRQ(ierr); 206 ierr = PetscVSNPrintf(next->string,QUEUESTRINGSIZE,format,Argp);CHKERRQ(ierr); 207 va_end(Argp); 208 } 209 210 PetscFunctionReturn(0); 211 } 212 213 #undef __FUNCT__ 214 #define __FUNCT__ "PetscSynchronizedFPrintf" 215 /*@C 216 PetscSynchronizedFPrintf - Prints synchronized output to the specified file from 217 several processors. Output of the first processor is followed by that of the 218 second, etc. 219 220 Not Collective 221 222 Input Parameters: 223 + comm - the communicator 224 . fd - the file pointer 225 - format - the usual printf() format string 226 227 Level: intermediate 228 229 Notes: 230 REQUIRES a intervening call to PetscSynchronizedFlush() for the information 231 from all the processors to be printed. 232 233 The length of the formatted message cannot exceed QUEUESTRINGSIZE characters. 234 235 Contributed by: Matthew Knepley 236 237 .seealso: PetscSynchronizedPrintf(), PetscSynchronizedFlush(), PetscFPrintf(), 238 PetscFOpen(), PetscViewerASCIISynchronizedPrintf(), PetscViewerASCIIPrintf() 239 240 @*/ 241 PetscErrorCode PETSC_DLLEXPORT PetscSynchronizedFPrintf(MPI_Comm comm,FILE* fp,const char format[],...) 242 { 243 PetscErrorCode ierr; 244 PetscMPIInt rank; 245 246 PetscFunctionBegin; 247 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); 248 249 /* First processor prints immediately to fp */ 250 if (!rank) { 251 va_list Argp; 252 va_start(Argp,format); 253 ierr = PetscVFPrintf(fp,format,Argp);CHKERRQ(ierr); 254 queuefile = fp; 255 if (petsc_history) { 256 ierr = PetscVFPrintf(petsc_history,format,Argp);CHKERRQ(ierr); 257 } 258 va_end(Argp); 259 } else { /* other processors add to local queue */ 260 va_list Argp; 261 PrintfQueue next; 262 ierr = PetscNew(struct _PrintfQueue,&next);CHKERRQ(ierr); 263 if (queue) {queue->next = next; queue = next; queue->next = 0;} 264 else {queuebase = queue = next;} 265 queuelength++; 266 va_start(Argp,format); 267 ierr = PetscMemzero(next->string,QUEUESTRINGSIZE);CHKERRQ(ierr); 268 ierr = PetscVSNPrintf(next->string,QUEUESTRINGSIZE,format,Argp);CHKERRQ(ierr); 269 va_end(Argp); 270 } 271 PetscFunctionReturn(0); 272 } 273 274 #undef __FUNCT__ 275 #define __FUNCT__ "PetscSynchronizedFlush" 276 /*@ 277 PetscSynchronizedFlush - Flushes to the screen output from all processors 278 involved in previous PetscSynchronizedPrintf() calls. 279 280 Collective on MPI_Comm 281 282 Input Parameters: 283 . comm - the communicator 284 285 Level: intermediate 286 287 Notes: 288 Usage of PetscSynchronizedPrintf() and PetscSynchronizedFPrintf() with 289 different MPI communicators REQUIRES an intervening call to PetscSynchronizedFlush(). 290 291 .seealso: PetscSynchronizedPrintf(), PetscFPrintf(), PetscPrintf(), PetscViewerASCIIPrintf(), 292 PetscViewerASCIISynchronizedPrintf() 293 @*/ 294 PetscErrorCode PETSC_DLLEXPORT PetscSynchronizedFlush(MPI_Comm comm) 295 { 296 PetscErrorCode ierr; 297 PetscMPIInt rank,size,tag,i,j,n; 298 char message[QUEUESTRINGSIZE]; 299 MPI_Status status; 300 FILE *fd; 301 302 PetscFunctionBegin; 303 ierr = PetscCommDuplicate(comm,&comm,&tag);CHKERRQ(ierr); 304 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); 305 ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr); 306 307 /* First processor waits for messages from all other processors */ 308 if (!rank) { 309 if (queuefile) { 310 fd = queuefile; 311 } else { 312 fd = PETSC_STDOUT; 313 } 314 for (i=1; i<size; i++) { 315 ierr = MPI_Recv(&n,1,MPI_INT,i,tag,comm,&status);CHKERRQ(ierr); 316 for (j=0; j<n; j++) { 317 ierr = MPI_Recv(message,QUEUESTRINGSIZE,MPI_CHAR,i,tag,comm,&status);CHKERRQ(ierr); 318 ierr = PetscFPrintf(comm,fd,"%s",message); 319 } 320 } 321 queuefile = PETSC_NULL; 322 } else { /* other processors send queue to processor 0 */ 323 PrintfQueue next = queuebase,previous; 324 325 ierr = MPI_Send(&queuelength,1,MPI_INT,0,tag,comm);CHKERRQ(ierr); 326 for (i=0; i<queuelength; i++) { 327 ierr = MPI_Send(next->string,QUEUESTRINGSIZE,MPI_CHAR,0,tag,comm);CHKERRQ(ierr); 328 previous = next; 329 next = next->next; 330 ierr = PetscFree(previous);CHKERRQ(ierr); 331 } 332 queue = 0; 333 queuelength = 0; 334 } 335 ierr = PetscCommDestroy(&comm);CHKERRQ(ierr); 336 PetscFunctionReturn(0); 337 } 338 339 /* ---------------------------------------------------------------------------------------*/ 340 341 #undef __FUNCT__ 342 #define __FUNCT__ "PetscFPrintf" 343 /*@C 344 PetscFPrintf - Prints to a file, only from the first 345 processor in the communicator. 346 347 Not Collective 348 349 Input Parameters: 350 + comm - the communicator 351 . fd - the file pointer 352 - format - the usual printf() format string 353 354 Level: intermediate 355 356 Fortran Note: 357 This routine is not supported in Fortran. 358 359 Concepts: printing^in parallel 360 Concepts: printf^in parallel 361 362 .seealso: PetscPrintf(), PetscSynchronizedPrintf(), PetscViewerASCIIPrintf(), 363 PetscViewerASCIISynchronizedPrintf(), PetscSynchronizedFlush() 364 @*/ 365 PetscErrorCode PETSC_DLLEXPORT PetscFPrintf(MPI_Comm comm,FILE* fd,const char format[],...) 366 { 367 PetscErrorCode ierr; 368 PetscMPIInt rank; 369 370 PetscFunctionBegin; 371 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); 372 if (!rank) { 373 va_list Argp; 374 va_start(Argp,format); 375 ierr = PetscVFPrintf(fd,format,Argp);CHKERRQ(ierr); 376 if (petsc_history) { 377 ierr = PetscVFPrintf(petsc_history,format,Argp);CHKERRQ(ierr); 378 } 379 va_end(Argp); 380 } 381 PetscFunctionReturn(0); 382 } 383 384 #undef __FUNCT__ 385 #define __FUNCT__ "PetscPrintf" 386 /*@C 387 PetscPrintf - Prints to standard out, only from the first 388 processor in the communicator. 389 390 Not Collective 391 392 Input Parameters: 393 + comm - the communicator 394 - format - the usual printf() format string 395 396 Level: intermediate 397 398 Fortran Note: 399 The call sequence is PetscPrintf(PetscViewer, character(*), PetscErrorCode ierr) from Fortran. 400 That is, you can only pass a single character string from Fortran. 401 402 Notes: %A is replace with %g unless the value is < 1.e-12 when it is 403 replaced with < 1.e-12 404 405 Concepts: printing^in parallel 406 Concepts: printf^in parallel 407 408 .seealso: PetscFPrintf(), PetscSynchronizedPrintf() 409 @*/ 410 PetscErrorCode PETSC_DLLEXPORT PetscPrintf(MPI_Comm comm,const char format[],...) 411 { 412 PetscErrorCode ierr; 413 PetscMPIInt rank; 414 size_t len; 415 char *nformat,*sub1,*sub2; 416 PetscReal value; 417 418 PetscFunctionBegin; 419 if (!comm) comm = PETSC_COMM_WORLD; 420 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); 421 if (!rank) { 422 va_list Argp; 423 va_start(Argp,format); 424 425 ierr = PetscStrstr(format,"%A",&sub1);CHKERRQ(ierr); 426 if (sub1) { 427 ierr = PetscStrstr(format,"%",&sub2);CHKERRQ(ierr); 428 if (sub1 != sub2) SETERRQ(PETSC_ERR_ARG_WRONG,"%%A format must be first in format string"); 429 ierr = PetscStrlen(format,&len);CHKERRQ(ierr); 430 ierr = PetscMalloc((len+16)*sizeof(char),&nformat);CHKERRQ(ierr); 431 ierr = PetscStrcpy(nformat,format);CHKERRQ(ierr); 432 ierr = PetscStrstr(nformat,"%",&sub2);CHKERRQ(ierr); 433 sub2[0] = 0; 434 value = (double)va_arg(Argp,double); 435 if (PetscAbsReal(value) < 1.e-12) { 436 ierr = PetscStrcat(nformat,"< 1.e-12");CHKERRQ(ierr); 437 } else { 438 ierr = PetscStrcat(nformat,"%g");CHKERRQ(ierr); 439 va_end(Argp); 440 va_start(Argp,format); 441 } 442 ierr = PetscStrcat(nformat,sub1+2);CHKERRQ(ierr); 443 } else { 444 nformat = (char*)format; 445 } 446 ierr = PetscVFPrintf(PETSC_STDOUT,nformat,Argp);CHKERRQ(ierr); 447 if (petsc_history) { 448 ierr = PetscVFPrintf(petsc_history,nformat,Argp);CHKERRQ(ierr); 449 } 450 va_end(Argp); 451 if (sub1) {ierr = PetscFree(nformat);CHKERRQ(ierr);} 452 } 453 PetscFunctionReturn(0); 454 } 455 456 /* ---------------------------------------------------------------------------------------*/ 457 #undef __FUNCT__ 458 #define __FUNCT__ "PetscHelpPrintfDefault" 459 PetscErrorCode PETSC_DLLEXPORT PetscHelpPrintfDefault(MPI_Comm comm,const char format[],...) 460 { 461 PetscErrorCode ierr; 462 PetscMPIInt rank; 463 464 PetscFunctionBegin; 465 if (!comm) comm = PETSC_COMM_WORLD; 466 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); 467 if (!rank) { 468 va_list Argp; 469 va_start(Argp,format); 470 ierr = PetscVFPrintf(PETSC_STDOUT,format,Argp);CHKERRQ(ierr); 471 if (petsc_history) { 472 ierr = PetscVFPrintf(petsc_history,format,Argp);CHKERRQ(ierr); 473 } 474 va_end(Argp); 475 } 476 PetscFunctionReturn(0); 477 } 478 479 /* ---------------------------------------------------------------------------------------*/ 480 481 static char arch[10],hostname[64],username[16],pname[PETSC_MAX_PATH_LEN],date[64]; 482 static PetscTruth PetscErrorPrintfInitializeCalled = PETSC_FALSE; 483 484 #undef __FUNCT__ 485 #define __FUNCT__ "PetscErrorPrintfInitialize" 486 /* 487 Initializes arch, hostname, username,date so that system calls do NOT need 488 to be made during the error handler. 489 */ 490 PetscErrorCode PETSC_DLLEXPORT PetscErrorPrintfInitialize() 491 { 492 PetscErrorCode ierr; 493 494 PetscFunctionBegin; 495 ierr = PetscGetArchType(arch,10);CHKERRQ(ierr); 496 ierr = PetscGetHostName(hostname,64);CHKERRQ(ierr); 497 ierr = PetscGetUserName(username,16);CHKERRQ(ierr); 498 ierr = PetscGetProgramName(pname,PETSC_MAX_PATH_LEN);CHKERRQ(ierr); 499 ierr = PetscGetDate(date,64);CHKERRQ(ierr); 500 PetscErrorPrintfInitializeCalled = PETSC_TRUE; 501 PetscFunctionReturn(0); 502 } 503 504 505 #undef __FUNCT__ 506 #define __FUNCT__ "PetscErrorPrintfDefault" 507 PetscErrorCode PETSC_DLLEXPORT PetscErrorPrintfDefault(const char format[],...) 508 { 509 va_list Argp; 510 static PetscTruth PetscErrorPrintfCalled = PETSC_FALSE; 511 static PetscTruth InPetscErrorPrintfDefault = PETSC_FALSE; 512 static FILE *fd; 513 char version[256]; 514 PetscErrorCode ierr; 515 516 /* 517 InPetscErrorPrintfDefault is used to prevent the error handler called (potentially) 518 from PetscSleep(), PetscGetArchName(), ... below from printing its own error message. 519 */ 520 521 /* 522 This function does not call PetscFunctionBegin and PetscFunctionReturn() because 523 it may be called by PetscStackView(). 524 525 This function does not do error checking because it is called by the error handlers. 526 */ 527 528 if (!PetscErrorPrintfCalled) { 529 PetscTruth use_stderr; 530 531 PetscErrorPrintfCalled = PETSC_TRUE; 532 InPetscErrorPrintfDefault = PETSC_TRUE; 533 534 PetscOptionsHasName(PETSC_NULL,"-error_output_stderr",&use_stderr); 535 if (use_stderr) { 536 fd = stderr; 537 } else { 538 fd = PETSC_STDOUT; 539 } 540 541 /* 542 On the SGI machines and Cray T3E, if errors are generated "simultaneously" by 543 different processors, the messages are printed all jumbled up; to try to 544 prevent this we have each processor wait based on their rank 545 */ 546 #if defined(PETSC_CAN_SLEEP_AFTER_ERROR) 547 { 548 PetscMPIInt rank; 549 if (PetscGlobalRank > 8) rank = 8; else rank = PetscGlobalRank; 550 PetscSleep(rank); 551 } 552 #endif 553 554 ierr = PetscGetVersion(&version);CHKERRQ(ierr); 555 556 PetscFPrintf(PETSC_COMM_SELF,fd,"------------------------------------------------------------------------\n"); 557 PetscFPrintf(PETSC_COMM_SELF,fd,"%s\n",version); 558 PetscFPrintf(PETSC_COMM_SELF,fd,"See docs/changes/index.html for recent updates.\n"); 559 PetscFPrintf(PETSC_COMM_SELF,fd,"See docs/faq.html for hints about trouble shooting.\n"); 560 PetscFPrintf(PETSC_COMM_SELF,fd,"See docs/index.html for manual pages.\n"); 561 PetscFPrintf(PETSC_COMM_SELF,fd,"------------------------------------------------------------------------\n"); 562 if (PetscErrorPrintfInitializeCalled) { 563 PetscFPrintf(PETSC_COMM_SELF,fd,"%s on a %s named %s by %s %s\n",pname,arch,hostname,username,date); 564 } 565 PetscFPrintf(PETSC_COMM_SELF,fd,"Libraries linked from %s\n",PETSC_LIB_DIR); 566 PetscFPrintf(PETSC_COMM_SELF,fd,"Configure run at %s\n",petscconfigureruntime); 567 PetscFPrintf(PETSC_COMM_SELF,fd,"Configure options %s\n",petscconfigureoptions); 568 InPetscErrorPrintfDefault = PETSC_FALSE; 569 } 570 571 if (!InPetscErrorPrintfDefault) { 572 PetscFPrintf(PETSC_COMM_SELF,fd,"[%d]PETSC ERROR: ",PetscGlobalRank); 573 va_start(Argp,format); 574 PetscVFPrintf(fd,format,Argp); 575 va_end(Argp); 576 } 577 return 0; 578 } 579 580 #undef __FUNCT__ 581 #define __FUNCT__ "PetscSynchronizedFGets" 582 /*@C 583 PetscSynchronizedFGets - Several processors all get the same line from a file. 584 585 Collective on MPI_Comm 586 587 Input Parameters: 588 + comm - the communicator 589 . fd - the file pointer 590 - len - the length of the output buffer 591 592 Output Parameter: 593 . string - the line read from the file 594 595 Level: intermediate 596 597 .seealso: PetscSynchronizedPrintf(), PetscSynchronizedFlush(), 598 PetscFOpen(), PetscViewerASCIISynchronizedPrintf(), PetscViewerASCIIPrintf() 599 600 @*/ 601 PetscErrorCode PETSC_DLLEXPORT PetscSynchronizedFGets(MPI_Comm comm,FILE* fp,size_t len,char string[]) 602 { 603 PetscErrorCode ierr; 604 PetscMPIInt rank; 605 606 PetscFunctionBegin; 607 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); 608 609 if (!rank) { 610 fgets(string,len,fp); 611 } 612 ierr = MPI_Bcast(string,len,MPI_BYTE,0,comm);CHKERRQ(ierr); 613 PetscFunctionReturn(0); 614 } 615