00001
00071
00072 #include "scatter.h"
00073
00074 #ifndef TOOLBOX
00075
00076 #define DEFAULT_MASS_RATIO 1
00077 #define DEFAULT_ECC 0
00078 #define DEFAULT_SMA 1
00079 #define SMA_REDUCE 10
00080 #define DEFAULT_R1 0
00081 #define DEFAULT_R2 0
00082
00083 #define TIDAL_TOL_FACTOR 1e-6
00084
00085 local void pp(sdyn* b, ostream & s, int level = 0) {
00086
00087 s.precision(4);
00088
00089 for (int i = 0; i < 2*level; i++) s << " ";
00090
00091 b->pretty_print_node(s);
00092 s << " \t"<< b->get_mass() << " \t"
00093 << b->get_pos() << " "
00094 << b->get_vel() <<endl;
00095
00096 for (sdyn * daughter = b->get_oldest_daughter();
00097 daughter != NULL;
00098 daughter = daughter->get_younger_sister())
00099 pp(daughter, s, level + 1);
00100 }
00101
00102
00103
00104
00105
00106
00107 local void initialize_root(sdyn* root, real v_inf,
00108 real rho_sq_min, real rho_sq_max, real peri,
00109 real r_init,
00110 real projectile_mass, real projectile_radius) {
00111
00112
00113
00114
00115
00116
00117 real target_mass = 1;
00118 real target_sma = 1;
00119
00120 real m_total = target_mass + projectile_mass;
00121 root->set_mass(m_total);
00122 root->set_pos(vector(0,0,0));
00123 root->set_vel(vector(0,0,0));
00124
00125 sdyn* target = root->get_oldest_daughter();
00126 target->set_mass(target_mass);
00127 target->set_radius(target_sma);
00128
00129 sdyn* projectile = target->get_younger_sister();
00130 projectile->set_mass(projectile_mass);
00131 projectile->set_radius(projectile_radius);
00132
00133
00134
00135 v_inf *= sqrt(0.5*m_total);
00136
00137
00138 if (rho_sq_max*peri > 0) err_exit("Inconsistent initial conditions.");
00139
00140 real rho_max = -1;
00141 if(rho_sq_max>0)
00142 rho_max = sqrt(rho_sq_max);
00143
00144 if (peri > 0) {
00145 if (v_inf > 0)
00146 rho_max = peri * sqrt(1 + 2*m_total/(peri*v_inf*v_inf));
00147 else
00148 rho_max = peri;
00149 }
00150
00151
00152 real rho = sqrt(randinter(rho_sq_min, pow(rho_max, 2)));
00153
00154
00155
00156
00157 real energy = .5 * v_inf * v_inf;
00158 real ang_mom = rho * v_inf;
00159
00160 real ecc = (energy == 0 ? 1 : sqrt( 1 + 2 * energy
00161 * pow(ang_mom/m_total, 2)));
00162
00163
00164
00165 real virial_ratio = rho;
00166
00167 kepler k;
00168
00169
00170
00171 make_standard_kepler(k, 0, m_total, energy, ecc, virial_ratio, -0.001, 1);
00172
00173
00174
00175 real r_unp = (target_sma + projectile_radius)
00176 * pow(TIDAL_TOL_FACTOR / m_total, -1/3.0);
00177
00178 real r_start = min(r_init, r_unp);
00179 if (k.get_separation() < r_start)
00180 k.return_to_radius(r_start);
00181 else
00182 k.advance_to_radius(r_start);
00183
00184
00185
00186 root->set_time(k.get_time());
00187 target->set_time(k.get_time());
00188 projectile->set_time(k.get_time());
00189
00190 target->set_pos(-projectile_mass * k.get_rel_pos() / m_total);
00191 target->set_vel(-projectile_mass * k.get_rel_vel() / m_total);
00192
00193 projectile->set_pos(target_mass * k.get_rel_pos() / m_total);
00194 projectile->set_vel(target_mass * k.get_rel_vel() / m_total);
00195
00196
00197
00198
00199
00200
00201
00202
00203 }
00204
00205
00206
00207
00208
00209
00210 local void split_particle(sdyn* current, real ecc, real sma, int planar,
00211 real mass_ratio, real r1, real r2) {
00212
00213 if (current->get_oldest_daughter() != NULL)
00214 err_exit("Can't split a binary node!");
00215
00216
00217
00218 sdyn* d1 = new sdyn;
00219 sdyn* d2 = new sdyn;
00220
00221 current->set_oldest_daughter(d1);
00222
00223 d1->set_parent(current);
00224 d2->set_parent(current);
00225
00226 d1->set_younger_sister(d2);
00227 d2->set_elder_sister(d1);
00228
00229
00230
00231 real m_total = current->get_mass();
00232 real m1 = m_total / (1 + mass_ratio);
00233 real m2 = m1 * mass_ratio;
00234
00235
00236
00237 if (m1 < m2) {
00238 real temp = m1;
00239 m1 = m2;
00240 m2 = temp;
00241 }
00242
00243 d1->set_mass(m1);
00244 d2->set_mass(m2);
00245
00246
00247 d1->set_radius(r1);
00248 d2->set_radius(r2);
00249
00250
00251 d2->get_parent()->set_radius(0);
00252
00253
00254
00255 kepler k;
00256
00257 if (sma < 0) {
00258 sma = DEFAULT_SMA;
00259 for (int i = 1; i < strlen(current->get_name()); i++)
00260 sma /= SMA_REDUCE;
00261 }
00262
00263 if (ecc < 0 || ecc >= 1) {
00264
00265
00266 real peri_min = 2*max(d1->get_radius(), d2->get_radius());
00267 real e_max = 1 - peri_min/sma;
00268
00269 if(e_max<0)
00270 err_exit("initial eccentricity out of bounds in split_particle(...)");
00271
00272
00273 if(STABILITY)
00274 ecc = sqrt(randinter(0, e_max*e_max));
00275 else
00276 ecc = sqrt(randinter(0,1));
00277 }
00278
00279
00280
00281
00282
00283 real peri = 1;
00284 if (ecc == 1) peri = 0;
00285
00286
00287
00288 real mean_anomaly = randinter(-PI, PI);
00289
00290 make_standard_kepler(k, 0, m_total, -0.5 * m_total / sma, ecc,
00291 peri, mean_anomaly);
00292
00293 set_random_orientation(k, planar);
00294
00295 d1->set_time(current->get_time());
00296 d2->set_time(current->get_time());
00297
00298 d1->set_pos(-m2 * k.get_rel_pos() / m_total);
00299 d1->set_vel(-m2 * k.get_rel_vel() / m_total);
00300
00301 d2->set_pos(m1 * k.get_rel_pos() / m_total);
00302 d2->set_vel(m1 * k.get_rel_vel() / m_total);
00303
00304
00305
00306 d1->set_name(current->get_name());
00307 d2->set_name(current->get_name());
00308 strcat(d1->get_name(), "1");
00309 strcat(d2->get_name(), "2");
00310
00311
00312
00313 }
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323 #include <string.h>
00324 local sdyn* locate_label_and_set_defaults(sdyn* root, char* label, int planar) {
00325
00326 sdyn* b = root;
00327
00328 for (int i = 0; i < strlen(label); i++) {
00329
00330 char* name = strdup(label);
00331 name[i+1] = '\0';
00332
00333 sdyn* node = NULL;
00334
00335
00336
00337 while (node == NULL) {
00338 for_all_daughters(sdyn, b, bb)
00339 if (strcmp(bb->get_name(), name) == 0) node = bb;
00340 if (node == NULL) {
00341 if (b->get_oldest_daughter() != NULL) return NULL;
00342
00343
00344
00345 split_particle(b, DEFAULT_ECC, -1, planar,
00346 DEFAULT_MASS_RATIO, DEFAULT_R1, DEFAULT_R2);
00347 }
00348
00349
00350 }
00351 b = node;
00352 }
00353 return b;
00354 }
00355
00356
00357
00358
00359 sdyn* first_leaf(sdyn* b)
00360 {
00361 while (b->get_oldest_daughter()) b = b->get_oldest_daughter();
00362 return b;
00363 }
00364
00365
00366
00367 sdyn* next_leaf(sdyn* b)
00368 {
00369 if (b == NULL)
00370
00371 return NULL;
00372
00373 else if (b->get_oldest_daughter())
00374
00375 return first_leaf(b);
00376
00377 else
00378
00379 while (b != NULL && b->get_younger_sister() == NULL)
00380 b = b->get_parent();
00381
00382 return (b == NULL ? (sdyn*)NULL : first_leaf(b->get_younger_sister()));
00383 }
00384
00385 sdyn* mkscat(int argc, char **argv) {
00386
00387
00388
00389 sdyn* root = mksdyn(2);
00390 root->set_name("r");
00391 root->set_index(-1);
00392
00393 sdyn* target = root->get_oldest_daughter();
00394 target->set_name("t");
00395 target->set_index(-1);
00396
00397 sdyn* projectile = target->get_younger_sister();
00398 projectile->set_name("p");
00399 projectile->set_index(-1);
00400
00401 sdyn* current = root;
00402
00403
00404
00405 real projectile_mass = 1;
00406 real projectile_radius = 0;
00407 real v_inf = 1;
00408 real rho = 0;
00409 real rho_sq = 0;
00410 real peri = -1;
00411 real initial_separation = VERY_LARGE_NUMBER;
00412
00413 real mass_ratio = DEFAULT_MASS_RATIO;
00414 real ecc = DEFAULT_ECC;
00415 real sma = DEFAULT_SMA;
00416 real r1 = DEFAULT_R1;
00417 real r2 = DEFAULT_R2;
00418
00419 int planar = 0;
00420 bool debug = FALSE;
00421
00422
00423
00424 int seed = 0;
00425 int i = 0;
00426 int random_seed;
00427 while (++i < argc)
00428 if (argv[i][0] == '-' && argv[i][1] == 's') {
00429 seed = atoi(argv[++i]);
00430 if(seed!=0)
00431 random_seed = srandinter(seed);
00432 else
00433 cerr << "Seed not re-initialized" << endl;
00434 seed = -1;
00435 }
00436 if(seed>0)
00437 random_seed = srandinter(seed);
00438
00439
00440
00441 i = 0;
00442 while (++i < argc) if (argv[i][0] == '-')
00443 switch (argv[i][1]) {
00444
00445
00446
00447 case 'M': if (current != root) cerr <<
00448 "Too late to initialize projectile mass!\n";
00449 projectile_mass = atof(argv[++i]);
00450 break;
00451 case 'R': projectile_radius = atof(argv[++i]);
00452 break;
00453 case 'r': switch(argv[i][2]) {
00454 case '\0': if (current != root) cerr <<
00455 "Too late to initialize impact parameter!\n";
00456 rho = atof(argv[++i]);
00457 rho_sq = rho*rho;
00458 peri = -1;
00459 break;
00460 case 'm': if (current != root) cerr <<
00461 "Too late to initialize pericenter!\n";
00462 peri = atof(argv[++i]);
00463 rho = -1;
00464 rho_sq = -1;
00465 break;
00466 case '1': r1 = atof(argv[++i]);
00467 break;
00468 case '2': r2 = atof(argv[++i]);
00469 break;
00470 default: cerr << "Incorrect 'r' flag ignored\n";
00471 break;
00472 }
00473 break;
00474 case 'S': initial_separation = atof(argv[++i]);
00475 break;
00476 case 'v': if (current != root) cerr <<
00477 "Too late to initialize velocity at infinity!\n";
00478 v_inf = atof(argv[++i]);
00479 break;
00480
00481
00482
00483 case 'p':
00484 case 't': if (current == root)
00485 initialize_root(root, v_inf, rho_sq, rho_sq, peri,
00486 initial_separation,
00487 projectile_mass, projectile_radius);
00488 else
00489 split_particle(current, ecc, sma, planar,
00490 mass_ratio, r1, r2);
00491
00492 current = locate_label_and_set_defaults(root,
00493 &argv[i][1],
00494 planar);
00495 if (current == NULL) err_exit("Illegal node name.");
00496
00497
00498
00499 mass_ratio = DEFAULT_MASS_RATIO;
00500
00501 ecc = sqrt(randinter(0, 1));
00502 sma = -1;
00503 r1 = DEFAULT_R1;
00504 r2 = DEFAULT_R2;
00505
00506 break;
00507
00508
00509
00510 case 'a': sma = atof(argv[++i]);
00511 break;
00512 case 'e': ecc = atof(argv[++i]);
00513 break;
00514 case 'q': mass_ratio = atof(argv[++i]);
00515 break;
00516
00517 case 'P': switch(argv[i][2]) {
00518 case '-': planar = -1;
00519 break;
00520 case '0': planar = 0;
00521 break;
00522 case '+': planar = 1;
00523 break;
00524 case '\0': if (planar == 0)
00525 planar = 1;
00526 else
00527 planar = 0;
00528 break;
00529 default: cerr << "Incorrect 'P' flag ignored\n";
00530 break;
00531 }
00532 break;
00533
00534 case 'd': debug = 1 - debug;
00535 break;
00536 case 's': break;
00537
00538 default: cerr << "usage: mkscat [-d] [-s #]"
00539 << " [-M #] [-r #] [-rm #] [-v #] [-R #] [-S #]"
00540 << " [ -t/p... [-a #] [-e #] [-q #] [-P[+/-]"
00541 << " [-r1 #] [-r2 #] ] [-t/p... ...]"
00542 << endl;
00543 exit(1);
00544 }
00545
00546
00547
00548 if (current == root)
00549 initialize_root(root, v_inf, rho_sq, rho_sq, peri, initial_separation,
00550 projectile_mass, projectile_radius);
00551 else
00552 split_particle(current, ecc, sma, planar,
00553 mass_ratio, r1, r2);
00554
00555
00556
00557
00558 int id = 0;
00559 sdyn* b = first_leaf(root);
00560 while (b) {
00561 b->set_index(++id);
00562 b = next_leaf(b);
00563 }
00564
00565
00566
00567 root->log_history(argc, argv);
00568
00569 char seedlog[80];
00570 sprintf(seedlog, " random seed = %d",
00571 random_seed);
00572 root->log_comment(seedlog);
00573
00574 if (0) {
00575 cerr << "mkscat: pretty-print system (seed = "
00576 << random_seed << "):\n";
00577 pp(root, cerr);
00578 }
00579
00580 return root;
00581 }
00582
00583 sdyn* mkscat(int argc, char **argv, scatter_profile &prof) {
00584
00585
00586
00587
00588 sdyn* root = mksdyn(2);
00589 root->set_name("r");
00590 root->set_index(-1);
00591
00592 sdyn* target = root->get_oldest_daughter();
00593 target->set_name("t");
00594 target->set_index(-1);
00595
00596 sdyn* projectile = target->get_younger_sister();
00597 projectile->set_name("p");
00598 projectile->set_index(-1);
00599
00600 sdyn* current = root;
00601
00602
00603
00604 real projectile_mass = 1;
00605 real projectile_radius = 0;
00606 real v_inf = 1;
00607 real rho = 0;
00608 real peri = -1;
00609 real initial_separation = VERY_LARGE_NUMBER;
00610
00611 real mass_ratio = DEFAULT_MASS_RATIO;
00612 real ecc = DEFAULT_ECC;
00613 real sma = DEFAULT_SMA;
00614 real r1 = DEFAULT_R1;
00615 real r2 = DEFAULT_R2;
00616
00617 int planar = 0;
00618 bool debug = FALSE;
00619
00620
00621
00622 int seed = 0;
00623 int i = 0;
00624 int random_seed;
00625 while (++i < argc)
00626 if (argv[i][0] == '-' && argv[i][1] == 's') {
00627 seed = atoi(argv[++i]);
00628 if(seed!=0)
00629 random_seed = srandinter(seed);
00630 else
00631 cerr << "Seed not re-initialized" << endl;
00632 seed = -1;
00633 }
00634 if(seed>0)
00635 random_seed = srandinter(seed);
00636
00637
00638
00639 i = 0;
00640 while (++i < argc) if (argv[i][0] == '-')
00641 switch (argv[i][1]) {
00642
00643
00644
00645 case 'M': if (current != root) cerr <<
00646 "Too late to initialize projectile mass!\n";
00647 projectile_mass = atof(argv[++i]);
00648 prof.mp = projectile_mass;
00649 break;
00650 case 'R': projectile_radius = atof(argv[++i]);
00651 prof.ap = projectile_radius;
00652 break;
00653 case 'r': switch(argv[i][2]) {
00654 case '\0': if (current != root) cerr <<
00655 "Too late to initialize impact parameter!\n";
00656 if(prof.rho_sq_max<0 && prof.peri<0) {
00657 rho = atof(argv[++i]);
00658 peri = -1;
00659 prof.rho_sq_max = rho*rho;
00660 prof.peri = -1;
00661 }
00662 break;
00663 case 'm': if (current != root) cerr <<
00664 "Too late to initialize pericenter!\n";
00665 if(prof.rho_sq_max<0 && prof.peri<0) {
00666 peri = atof(argv[++i]);
00667 rho = -1;
00668 prof.peri = peri;
00669 prof.rho_sq_max = rho;
00670 }
00671 break;
00672 case '1': r1 = atof(argv[++i]);
00673 break;
00674 case '2': r2 = atof(argv[++i]);
00675 break;
00676 default: cerr << "Incorrect 'r' flag ignored\n";
00677 break;
00678 }
00679 break;
00680 case 'S': initial_separation = atof(argv[++i]);
00681 break;
00682 case 'v': if (current != root) cerr <<
00683 "Too late to initialize velocity at infinity!\n";
00684 if(prof.rho_sq_max<0 && prof.peri<0) {
00685 v_inf = atof(argv[++i]);
00686 prof.v_inf = v_inf;
00687 }
00688 break;
00689
00690
00691
00692 case 'p':
00693 case 't': if (current == root)
00694 initialize_root(root, prof.v_inf,
00695 prof.rho_sq_min, prof.rho_sq_max,
00696 prof.peri,
00697 initial_separation,
00698 projectile_mass, projectile_radius);
00699 else
00700 split_particle(current, ecc, sma, planar,
00701 mass_ratio, r1, r2);
00702
00703 current = locate_label_and_set_defaults(root,
00704 &argv[i][1],
00705 planar);
00706 if (current == NULL) err_exit("Illegal node name.");
00707
00708
00709
00710 mass_ratio = DEFAULT_MASS_RATIO;
00711
00712 ecc = sqrt(randinter(0, 1));
00713 sma = -1;
00714 r1 = DEFAULT_R1;
00715 r2 = DEFAULT_R2;
00716
00717 break;
00718
00719
00720
00721 case 'a': sma = atof(argv[++i]);
00722 break;
00723 case 'e': ecc = atof(argv[++i]);
00724 break;
00725 case 'q': mass_ratio = atof(argv[++i]);
00726 break;
00727
00728 case 'P': switch(argv[i][2]) {
00729 case '-': planar = -1;
00730 break;
00731 case '0': planar = 0;
00732 break;
00733 case '+': planar = 1;
00734 break;
00735 case '\0': if (planar == 0)
00736 planar = 1;
00737 else
00738 planar = 0;
00739 break;
00740 default: cerr << "Incorrect 'P' flag ignored\n";
00741 break;
00742 }
00743 break;
00744
00745 case 'd': debug = 1 - debug;
00746 break;
00747 case 's': break;
00748
00749 default: cerr << "usage: mkscat [-d] [-s #]"
00750 << " [-M #] [-r #] [-rm #] [-v #] [-R #] [-S #]"
00751 << " [ -t/p... [-a #] [-e #] [-q #] [-P[+/-]"
00752 << " [-r1 #] [-r2 #] ] [-t/p... ...]"
00753 << endl;
00754 exit(1);
00755 }
00756
00757
00758
00759 if (current == root)
00760 initialize_root(root, prof.v_inf, prof.rho_sq_min, prof.rho_sq_max,
00761 prof.peri,
00762 initial_separation,
00763 projectile_mass, projectile_radius);
00764 else
00765 split_particle(current, ecc, sma, planar,
00766 mass_ratio, r1, r2);
00767
00768
00769
00770
00771 int id = 0;
00772 sdyn* b = first_leaf(root);
00773 while (b) {
00774 b->set_index(++id);
00775 b = next_leaf(b);
00776 }
00777
00778
00779
00780 root->log_history(argc, argv);
00781
00782 char seedlog[80];
00783 sprintf(seedlog, " random seed = %d",
00784 random_seed);
00785 root->log_comment(seedlog);
00786
00787 if (0) {
00788 cerr << "mkscat: pretty-print system (seed = "
00789 << random_seed << "):\n";
00790 pp(root, cerr);
00791 }
00792
00793 return root;
00794 }
00795
00796 #define TEXT_BUFFER_SIZE 1024
00797
00798 static char temp[TEXT_BUFFER_SIZE];
00799 static char* name = "parse_string";
00800
00801
00802
00803
00804
00805 void parse_string(char* s, int& argc, char* argv[]) {
00806
00807 int length = strlen(s);
00808 if (length >= TEXT_BUFFER_SIZE) err_exit("String too long.");
00809
00810 argv[0] = name;
00811 argc = 1;
00812
00813 int first = 0, last = -1;
00814
00815 for (int i = 0; i <= length; i++) {
00816 temp[i] = s[i];
00817 if (temp[i] == ' ' || i == length) {
00818 if (last >= 0) {
00819 temp[i] = '\0';
00820 argv[argc++] = temp + first;
00821 }
00822 last = -1;
00823 } else {
00824 if (last < 0) first = i;
00825 last = i;
00826 }
00827 }
00828 }
00829
00830
00831 #define MAX_ARGS 256
00832
00833 sdyn* mkscat(char* s, scatter_profile &prof) {
00834
00835 int argc;
00836 char* argv[MAX_ARGS];
00837
00838 parse_string(s, argc, argv);
00839 if (argc > MAX_ARGS) err_exit("Too many arguments.");
00840
00841 return mkscat(argc, argv, prof);
00842 }
00843
00844 sdyn* mkscat(char* s) {
00845
00846 int argc;
00847 char* argv[MAX_ARGS];
00848
00849 parse_string(s, argc, argv);
00850 if (argc > MAX_ARGS) err_exit("Too many arguments.");
00851
00852 return mkscat(argc, argv);
00853 }
00854
00855 #else
00856
00857 main(int argc, char** argv) {
00858 check_help();
00859
00860
00861 }
00862
00863 #endif