Geant4 Cross Reference |
1 // 2 // ******************************************************************** 3 // * License and Disclaimer * 4 // * * 5 // * The Geant4 software is copyright of the Copyright Holders of * 6 // * the Geant4 Collaboration. It is provided under the terms and * 7 // * conditions of the Geant4 Software License, included in the file * 8 // * LICENSE and available at http://cern.ch/geant4/license . These * 9 // * include a list of copyright holders. * 10 // * * 11 // * Neither the authors of this software system, nor their employing * 12 // * institutes,nor the agencies providing financial support for this * 13 // * work make any representation or warranty, express or implied, * 14 // * regarding this software system or assume any liability for its * 15 // * use. Please see the license in the file LICENSE and URL above * 16 // * for the full disclaimer and the limitation of liability. * 17 // * * 18 // * This code implementation is the result of the scientific and * 19 // * technical work of the GEANT4 collaboration. * 20 // * By using, copying, modifying or distributing the software (or * 21 // * any work based on the software) you agree to acknowledge its * 22 // * use in resulting scientific publications, and indicate your * 23 // * acceptance of all terms of the Geant4 Software license. * 24 // ******************************************************************** 25 // 26 // G4tgrUtils implementation 27 // 28 // Author: P.Arce, CIEMAT (November 2007) 29 // -------------------------------------------------------------------- 30 31 #include <iomanip> 32 #include <set> 33 34 #include "G4tgrUtils.hh" 35 36 #include "geomdefs.hh" 37 #include "G4PhysicalConstants.hh" 38 #include "G4tgrParameterMgr.hh" 39 #include "G4tgrMessenger.hh" 40 #include "G4UnitsTable.hh" 41 #include "G4GeometryTolerance.hh" 42 #include "G4UIcommand.hh" 43 44 G4ThreadLocal G4tgrEvaluator* G4tgrUtils::theEvaluator = nullptr; 45 46 // -------------------------------------------------------------------- 47 G4tgrUtils::G4tgrUtils() 48 { 49 if(theEvaluator == nullptr) 50 { 51 theEvaluator = new G4tgrEvaluator; 52 } 53 } 54 55 // -------------------------------------------------------------------- 56 G4tgrUtils::~G4tgrUtils() 57 { 58 delete theEvaluator; 59 theEvaluator = nullptr; 60 } 61 62 // -------------------------------------------------------------------- 63 G4bool G4tgrUtils::IsSeparator(const char ch) 64 { 65 char nonCharacters[7] = { "()+-*/" }; 66 for(std::size_t ii = 0; ii < 6; ++ii) 67 { 68 if(ch == nonCharacters[ii]) 69 { 70 return true; 71 } 72 } 73 return false; 74 } 75 76 // -------------------------------------------------------------------- 77 G4bool G4tgrUtils::IsNumber(const G4String& str) 78 { 79 G4int isnum = 1; 80 G4int numE = 0; 81 for(G4int ii = 0; ii < (G4int)str.length(); ++ii) 82 { 83 if(!isdigit(str[ii]) && (str[ii] != '.') && (str[ii] != '-') && 84 (str[ii] != '+')) 85 { 86 //--- check for E(xponential) 87 if(str[ii] == 'E' || str[ii] == 'e') 88 { 89 if(ii == 0) 90 { 91 return 0; 92 } 93 if(numE != 0 || ii == G4int(str.length() - 1)) 94 { 95 isnum = 0; 96 break; 97 } 98 numE++; 99 } 100 else 101 { 102 isnum = 0; 103 break; 104 } 105 } 106 } 107 return isnum; 108 } 109 110 // -------------------------------------------------------------------- 111 G4bool G4tgrUtils::IsInteger(const G4double val, const G4double precision) 112 { 113 if(G4int(val) / val - 1 > precision) 114 { 115 return false; 116 } 117 else 118 { 119 return true; 120 } 121 } 122 123 // -------------------------------------------------------------------- 124 void G4tgrUtils::Dump3v(const G4ThreeVector& vec, const char* msg) 125 { 126 G4cout << msg << std::setprecision(8) << vec << std::setprecision(6) 127 << G4endl; 128 } 129 130 // -------------------------------------------------------------------- 131 void G4tgrUtils::Dumprm(const G4RotationMatrix& rm, const char* msg) 132 { 133 G4cout << msg << G4endl << " xx=" << rm.xx() << " yx=" << rm.yx() 134 << " zx=" << rm.zx() << G4endl << " xy=" << rm.xy() 135 << " yy=" << rm.yy() << " zy=" << rm.zy() << G4endl 136 << " xz=" << rm.xz() << " yz=" << rm.yz() << " zz=" << rm.zz() 137 << G4endl; 138 } 139 140 // -------------------------------------------------------------------- 141 void G4tgrUtils::DumpVS(const std::vector<G4String>& wl, const char* msg, 142 std::ostream& outs) 143 { 144 outs << msg << G4endl; 145 for(auto ite = wl.cbegin(); ite != wl.cend(); ++ite) 146 { 147 outs << *ite << " "; 148 } 149 outs << G4endl; 150 } 151 152 // -------------------------------------------------------------------- 153 void G4tgrUtils::DumpVS(const std::vector<G4String>& wl, const char* msg) 154 { 155 DumpVS(wl, msg, G4cout); 156 } 157 158 // -------------------------------------------------------------------- 159 G4String G4tgrUtils::SubColon(const G4String& str) 160 { 161 if(str.find(':') != 0) 162 { 163 G4String ErrMessage = "Trying to subtract leading colon from a word\n" + 164 G4String("that has no leading colon: ") + str; 165 G4Exception("G4tgrUtils::SubColon()", "ParseError", FatalException, 166 ErrMessage); 167 } 168 G4String strt = str.substr(1, str.size() - 1); 169 return strt; 170 } 171 172 // -------------------------------------------------------------------- 173 G4String G4tgrUtils::GetString(const G4String& str) 174 { 175 //----------- first check if it is parameter 176 const char* cstr = str.c_str(); 177 if(cstr[0] == '$') 178 { 179 #ifdef G4VERBOSE 180 if(G4tgrMessenger::GetVerboseLevel() >= 3) 181 { 182 G4cout << " G4tgrUtils::GetString() - Substitute parameter: " 183 << G4tgrParameterMgr::GetInstance()->FindParameter( 184 str.substr(1, str.size())) 185 << G4endl; 186 } 187 #endif 188 return G4tgrParameterMgr::GetInstance()->FindParameter( 189 str.substr(1, str.size())); 190 } 191 else 192 { 193 return str; 194 } 195 } 196 197 // -------------------------------------------------------------------- 198 G4double G4tgrUtils::GetDouble(const G4String& str, G4double unitval) 199 { 200 if(!theEvaluator) 201 { 202 theEvaluator = new G4tgrEvaluator; 203 } 204 #ifdef G4VERBOSE 205 if(G4tgrMessenger::GetVerboseLevel() >= 3) 206 { 207 G4cout << "G4tgrUtils::GetDouble() - Processing: " << str 208 << " default unit " << unitval << G4endl; 209 } 210 #endif 211 if(str == "DBL_MAX") 212 { 213 return DBL_MAX; 214 } 215 else if(str == "DBL_MIN") 216 { 217 return DBL_MIN; 218 } 219 else if(str == "FLT_MAX") 220 { 221 return FLT_MAX; 222 } 223 else if(str == "FLT_MIN") 224 { 225 return FLT_MIN; 226 } 227 else if(str == "INT_MAX") 228 { 229 return INT_MAX; 230 } 231 else if(str == "INT_MIN") 232 { 233 return INT_MIN; 234 } 235 //----- Look for arithmetic symbols, (, ) 236 const char* cstr = str.c_str(); 237 std::set<G4int> separators; 238 separators.insert(-1); 239 G4int strlen = G4int(str.length()); 240 for(G4int ii = 0; ii < strlen; ++ii) 241 { 242 char cs = cstr[ii]; 243 if(cs == '*' || cs == '/' || cs == '(' || cs == ')') 244 { 245 separators.insert(ii); 246 } 247 else if(cs == '+' || cs == '-') 248 { 249 // Check if it is not an exponential 250 // 251 if((ii < 2) || ((cstr[ii - 1] != 'E') && (cstr[ii - 1] != 'e')) || 252 !IsNumber(G4String(1,cstr[ii - 2]))) 253 { 254 separators.insert(ii); 255 } 256 } 257 } 258 separators.insert(strlen); 259 std::string strnew; // build a new word with Parameters 260 // and units substituted by values 261 //----- Process words, defined as characters between two separators 262 G4int nUnits = 0; 263 std::set<G4int>::const_iterator site, site2; 264 site = separators.cbegin(); 265 site2 = site; 266 ++site2; 267 for(; site2 != separators.cend(); ++site, ++site2) 268 { 269 #ifdef G4VERBOSE 270 if(G4tgrMessenger::GetVerboseLevel() >= 3) 271 { 272 G4cout << " Loop to find word between " << *site << " " << *site2 273 << G4endl; 274 } 275 #endif 276 277 if(*site != -1) 278 { 279 strnew += str.substr(*site, 1); 280 } 281 282 G4int wlen = (*site2) - (*site) - 1; // do not count contiguous separators 283 std::string word; 284 if(wlen != 0) 285 { 286 word = str.substr((*site) + 1, (*site2) - (*site) - 1); 287 } 288 else 289 { 290 //--- Check combination of separators 291 //--- Check number of parentheses 292 continue; 293 } 294 295 #ifdef G4VERBOSE 296 if(G4tgrMessenger::GetVerboseLevel() >= 3) 297 { 298 G4cout << " Processing word: " << word << G4endl; 299 } 300 #endif 301 //----------- first check if it is parameter 302 const char* cword = word.c_str(); 303 if(cword[0] == '$') 304 { 305 G4String parstr = G4tgrParameterMgr::GetInstance()->FindParameter( 306 word.substr(1, word.size())); 307 if(parstr.substr(0, 1) == "-") 308 { 309 strnew += "("; 310 } 311 strnew += parstr; 312 if(parstr.substr(0, 1) == "-") 313 { 314 strnew += ")"; 315 } 316 #ifdef G4VERBOSE 317 if(G4tgrMessenger::GetVerboseLevel() >= 3) 318 { 319 G4cout << " G4tgrutils::GetDouble() - Param found: " << word 320 << " in string " << str << " , substituted by " << parstr 321 << G4endl; 322 } 323 #endif 324 } 325 else 326 { 327 //----- Get if it is a number 328 if(IsNumber(word)) 329 { 330 //--- left separator cannot be ')' 331 if((*site != -1) && (cstr[*site] == ')')) 332 { 333 G4String ErrMessage = 334 "There cannot be a ')' before a number: " + word + 335 " in string: " + str; 336 G4Exception("G4tgrUtils::GetDouble()", "ParseError", FatalException, 337 ErrMessage); 338 } 339 //--- right separator cannot be '(' 340 if((*site2 != strlen) && (cstr[*site2] == '(')) 341 { 342 G4String ErrMessage = 343 "There cannot be a '(' after a number: " + word + 344 " in string: " + str; 345 G4Exception("G4tgrUtils::GetDouble()", "ParseError", FatalException, 346 ErrMessage); 347 } 348 strnew += word; 349 350 //------ If it is an string, check if it is a unit 351 } 352 else 353 { 354 //--- First character cannot be a digit 355 if(isdigit(word[0])) 356 { 357 G4String ErrMessage = 358 "String words cannot start with a digit: " + word + 359 " in string: " + str; 360 G4Exception("G4tgrUtils::GetDouble()", "ParseError", FatalException, 361 ErrMessage); 362 } 363 364 //----- Check if it is a function 365 G4bool bWordOK = false; 366 if(G4tgrUtils::IsFunction(word)) 367 { 368 //--- It must be followed by '(' 369 if((*site2 == strlen) || (cstr[*site2] != '(')) 370 { 371 G4String ErrMessage = 372 "There must be a '(' after a function: " + word + 373 " in string: " + str; 374 G4Exception("G4tgrUtils::GetDouble()", "ParseError", FatalException, 375 ErrMessage); 376 } 377 strnew += word; 378 bWordOK = true; 379 //----- Check if it is a unit 380 } 381 else if(G4tgrUtils::WordIsUnit(word)) 382 { 383 //--- It must be preceded by a * 384 if((*site == -1) || ((cstr[*site] != '*') && (cstr[*site] != '/'))) 385 { 386 G4String ErrMess = 387 "There must be a '*' before a unit definition: " + word + 388 " in string " + str; 389 G4Exception("G4tgrUtils::GetDouble()", "ParseError", FatalException, 390 ErrMess); 391 } 392 //--- check that it is indeed a CLHEP unit 393 if(G4UnitDefinition::GetValueOf(word) != 0.) 394 { 395 bWordOK = true; 396 nUnits++; 397 if(nUnits > 1) 398 { 399 // G4String ErrMess = "There cannot be two unit definitions: " 400 // + word + " in string " + str; 401 // G4Exception("G4tgrUtils::GetDouble()", "ParseError", 402 // FatalException, ErrMess ); 403 } 404 strnew += 405 G4UIcommand::ConvertToString(G4UnitDefinition::GetValueOf(word)); 406 } 407 } 408 if(!bWordOK) 409 { 410 G4String ErrMess = "String word is not a parameter, nor a unit\n" + 411 G4String("definition nor a function: ") + word + 412 G4String(" in string: ") + str; 413 G4Exception("G4tgrUtils::GetDouble()", "ParseError", FatalException, 414 ErrMess); 415 } 416 } 417 } 418 } 419 420 G4double val = theEvaluator->evaluate(strnew.c_str()); 421 if(theEvaluator->status() != HepTool::Evaluator::OK) 422 { 423 theEvaluator->print_error(theEvaluator->status()); 424 G4String ErrMessage = "Evaluator error: " + strnew; 425 G4Exception("G4tgrUtils::GetDouble()", "ParseError", FatalException, 426 ErrMessage); 427 } 428 429 if(nUnits == 0) 430 { 431 val *= unitval; 432 } 433 434 #ifdef G4VERBOSE 435 if(G4tgrMessenger::GetVerboseLevel() >= 3) 436 { 437 G4cout << " G4tgrUtils::GetDouble() - RESULT= " << val << G4endl 438 << " from string: " << str << " converted to: " << strnew.c_str() 439 << " with unit val: " << unitval << G4endl; 440 } 441 #endif 442 443 return val; 444 } 445 446 // -------------------------------------------------------------------- 447 G4int G4tgrUtils::GetInt(const G4String& str) 448 { 449 //----- Convert it to a number (it can be a parameter) 450 G4double val = GetDouble(str); 451 452 //----- Check it is an integer 453 if(!IsInteger(val)) 454 { 455 G4String ErrMessage = G4String("Trying to get the integer from a number") + 456 G4String(" which is not an integer ") + str; 457 G4Exception("G4tgrUtils::GetInt()", "ParseError", FatalException, 458 ErrMessage); 459 } 460 return G4int(val); 461 } 462 463 // -------------------------------------------------------------------- 464 G4bool G4tgrUtils::GetBool(const G4String& str) 465 { 466 G4bool val = false; 467 468 //----------- first check that it is a not number 469 if((str == "ON") || (str == "TRUE")) 470 { 471 val = true; 472 } 473 else if((str == "OFF") || (str == "FALSE")) 474 { 475 val = false; 476 } 477 else 478 { 479 G4String ErrMessage = G4String("Trying to get a float from a string") + 480 G4String(" which is not 'ON'/'OFF'/'TRUE'/'FALSE' ") + 481 str; 482 G4Exception("G4tgrUtils::GetBool()", "ParseError", FatalException, 483 ErrMessage); 484 } 485 486 return val; 487 } 488 489 // -------------------------------------------------------------------- 490 void G4tgrUtils::CheckWLsize(const std::vector<G4String>& wl, 491 unsigned int nWcheck, WLSIZEtype st, 492 const G4String& methodName) 493 { 494 G4String outStr = methodName + G4String(". Line read with number of words "); 495 unsigned int wlsize = (unsigned int)wl.size(); 496 497 G4bool isOK = CheckListSize(wlsize, nWcheck, st, outStr); 498 499 if(!isOK) 500 { 501 G4String chartmp = G4UIcommand::ConvertToString(G4int(nWcheck)); 502 outStr += chartmp + G4String(" words"); 503 DumpVS(wl, outStr.c_str()); 504 G4String ErrMessage = 505 " NUMBER OF WORDS: " + G4UIcommand::ConvertToString(G4int(wlsize)); 506 G4Exception("G4tgrUtils::CheckWLsize()", "ParseError", FatalException, 507 ErrMessage); 508 } 509 } 510 511 // -------------------------------------------------------------------- 512 G4bool G4tgrUtils::CheckListSize(unsigned int nWreal, unsigned int nWcheck, 513 WLSIZEtype st, G4String& outStr) 514 { 515 G4bool isOK = true; 516 switch(st) 517 { 518 case WLSIZE_EQ: 519 if(nWreal != nWcheck) 520 { 521 isOK = false; 522 outStr += G4String("not equal than "); 523 } 524 break; 525 case WLSIZE_NE: 526 if(nWreal == nWcheck) 527 { 528 isOK = false; 529 outStr += G4String("equal than "); 530 } 531 break; 532 case WLSIZE_LE: 533 if(nWreal > nWcheck) 534 { 535 isOK = false; 536 outStr += G4String("greater than "); 537 } 538 break; 539 case WLSIZE_LT: 540 if(nWreal >= nWcheck) 541 { 542 isOK = false; 543 outStr += G4String("greater or equal than "); 544 } 545 break; 546 case WLSIZE_GE: 547 if(nWreal < nWcheck) 548 { 549 isOK = false; 550 outStr += G4String("less than "); 551 } 552 break; 553 case WLSIZE_GT: 554 if(nWreal <= nWcheck) 555 { 556 isOK = false; 557 outStr += G4String("less or equal than "); 558 } 559 break; 560 default: 561 G4cerr << " ERROR!! - G4tgrUtils::CheckListSize()" << G4endl 562 << " Type of WLSIZE type not found " << st << G4endl; 563 break; 564 } 565 566 return isOK; 567 } 568 569 // -------------------------------------------------------------------- 570 G4bool G4tgrUtils::WordIsUnit(const G4String& word) 571 { 572 return !IsNumber(word); 573 if(word == "mm" || word == "cm" || word == "m" || word == "km" || 574 word == "millimeter" || word == "centimeter" || word == "meter" || 575 word == "kilometer" || word == "parsec" || word == "micrometer" || 576 word == "nanometer" || word == "angstrom" || word == "fermi" || 577 word == "nm" || word == "um" || word == "pc" || word == "radian" || 578 word == "milliradian" || word == "degree" || word == "rad" || 579 word == "mrad" || word == "deg" || word == "ns" || word == "becquerel" || 580 word == "curie") 581 { 582 return true; 583 } 584 else 585 { 586 return false; 587 } 588 } 589 590 // -------------------------------------------------------------------- 591 G4bool G4tgrUtils::IsFunction(const G4String& word) 592 { 593 if(word == "sin" || word == "cos" || word == "tan" || word == "asin" || 594 word == "acos" || word == "atan" || word == "atan2" || word == "sinh" || 595 word == "cosh" || word == "tanh" || word == "asinh" || word == "acosh" || 596 word == "atanh" || word == "sqrt" || word == "exp" || word == "log" || 597 word == "log10" || word == "pow") 598 { 599 return true; 600 } 601 else 602 { 603 return false; 604 } 605 } 606 607 // -------------------------------------------------------------------- 608 G4RotationMatrix G4tgrUtils::GetRotationFromDirection(G4ThreeVector dir) 609 { 610 G4RotationMatrix rotation; 611 612 if(std::fabs(dir.mag() - 1.) > 613 G4GeometryTolerance::GetInstance()->GetSurfaceTolerance()) 614 { 615 G4String WarMessage = "Direction cosines have been normalized to one.\n" + 616 G4String("They were normalized to ") + 617 G4UIcommand::ConvertToString(dir.mag()); 618 G4Exception("G4tgrUtils::GetRotationFromDirection()", "WrongArgument", 619 JustWarning, WarMessage); 620 dir /= dir.mag(); 621 } 622 G4double angx = -std::asin(dir.y()); 623 624 // There are always two solutions angx, angy and PI-angx, 625 // PI+angy, choose first 626 // 627 G4double angy; 628 if(dir.y() == 1.) 629 { 630 angy = 0.; 631 } 632 else if(dir.y() == 0.) 633 { 634 angy = 0.; 635 } 636 else 637 { 638 angy = std::asin(dir.x() / std::sqrt(1 - dir.y() * dir.y())); 639 } 640 641 // choose between angy and PI-angy 642 if(dir.z() * std::cos(angx) * std::cos(angy) < 0) 643 { 644 angy = pi - angy; 645 } 646 rotation.rotateX(angx); 647 rotation.rotateY(angy); 648 649 return rotation; 650 } 651 652 // -------------------------------------------------------------------- 653 G4bool G4tgrUtils::AreWordsEquivalent(const G4String& word1, 654 const G4String& word2) 655 { 656 G4bool bEqual = true; 657 std::vector<std::pair<size_t, size_t>> stringPairs; 658 // start of substring, number of characters 659 660 //--- Get string limits between asterisks in word1 661 662 std::size_t cStart = 0; 663 for(;;) 664 { 665 size_t cAster = word1.find("*", cStart); 666 if(cAster != std::string::npos) 667 { 668 if(cAster == cStart) 669 { 670 if(cAster != 0) 671 { 672 G4Exception("G4tgrUtils::AreWordsEquivalent()", 673 "A word has two asterisks together, please correct it", 674 FatalException, ("Offending word is: " + word1).c_str()); 675 } 676 else 677 { 678 // word1 == * 679 if(word1.size() == 1) 680 { 681 return true; 682 } 683 } 684 } 685 if(cAster != cStart) 686 { 687 stringPairs.push_back( 688 std::pair<size_t, size_t>(cStart, cAster - cStart)); 689 } 690 cStart = cAster + 1; 691 } 692 else 693 { 694 if(cStart == 0) 695 { 696 //--- If there is no asterisk check if they are the same 697 return word1 == word2; 698 } 699 break; 700 } 701 } 702 703 //---- Add characters after last asterisk as string pair 704 if(cStart <= word1.length()) 705 { 706 if(word1.length() != cStart) 707 { 708 stringPairs.push_back( 709 std::pair<size_t, size_t>(cStart, word1.length() - cStart)); 710 } 711 } 712 713 //--- If there are not asterisk, simple comparison 714 if(stringPairs.size() == 0) 715 { 716 if(word1 == word2) 717 { 718 return true; 719 } 720 else 721 { 722 return false; 723 } 724 } 725 726 //--- Find substrings in word2, in same order as in word1 727 cStart = 0; 728 for(std::size_t ii = 0; ii < stringPairs.size(); ++ii) 729 { 730 std::pair<size_t, size_t> spair = stringPairs[ii]; 731 size_t sFound = word2.find(word1.substr(spair.first, spair.second), cStart); 732 if(sFound == std::string::npos) 733 { 734 bEqual = false; 735 break; 736 } 737 else 738 { 739 //---- If there is no asterisk before first character, 740 // the fisrt string pair found has to start at the first character 741 if(spair.first == 0 && sFound != 0) 742 { 743 bEqual = false; 744 break; 745 //---- If there is no asterisk after last character, 746 // the last string pair found has to end at the last character 747 } 748 else if((spair.first + spair.second - 1 == word1.length()) && 749 (sFound + spair.second - 1 != word2.length())) 750 { 751 bEqual = false; 752 break; 753 } 754 cStart += spair.second; 755 } 756 } 757 758 return bEqual; 759 } 760