Main Page   Class Hierarchy   Data Structures   File List   Data Fields   Globals  

makesigm.C

Go to the documentation of this file.
00001 
00002 #include "../evolve/sigma.h"
00003 #ifndef TOOLBOX
00004 
00005 #define DEFAULT_MASS_RATIO 1
00006 #define DEFAULT_ECC 0
00007 #define DEFAULT_SMA 1
00008 #define SMA_REDUCE 10
00009 #define DEFAULT_R1 0
00010 #define DEFAULT_R2 0
00011 #define TIDAL_TOL_FACTOR 1e-6
00012 
00013 
00014 local void pp(sdyn* b, ostream & s, int level = 0) {
00015 
00016     s.precision(4);
00017 
00018     for (int i = 0; i < 2*level; i++) s << " ";
00019 
00020     b->pretty_print_node(s);
00021     s << " \t"<< b->get_mass() << " \t"
00022       << b->get_pos() << "   "
00023       << b->get_vel() <<endl;
00024 
00025     for (sdyn * daughter = b->get_oldest_daughter();
00026          daughter != NULL;
00027          daughter = daughter->get_younger_sister())
00028         pp(daughter, s, level + 1);     
00029 }
00030 
00031 // initialize_root: Set up the outermost (scattering) trajectory.
00032 //                  The plane and orientation of the trajectory define the
00033 //                  coordinate system used.  Assume a target semi-major
00034 //                  axis of 1 in determining the initial separation.
00035 
00036 local void initialize_root(sdyn* root, real v_inf, 
00037                            real rho_sq_min, real rho_sq_max, real peri,
00038                            real r_init,
00039                            real projectile_mass, real projectile_radius) {
00040 
00041   //  cerr << "Root: " << endl;
00042     //PRC(v_inf);PRC(rho_sq_min);PRC(rho_sq_max);PRC(peri);PRC(r_init);
00043     //    PRC(projectile_mass);PRL(projectile_radius);
00044     // Explicitly state target mass and radius:
00045 
00046     // NOTE that this will give unit radius to the target star in
00047     // a two-body encounter!
00048 
00049     real target_mass = 1;
00050     real target_sma = 1;
00051 
00052     real m_total = target_mass + projectile_mass;
00053     root->set_mass(m_total);
00054     root->set_pos(vector(0,0,0));
00055     root->set_vel(vector(0,0,0));
00056 
00057     sdyn* target = root->get_oldest_daughter();
00058     target->set_mass(target_mass);
00059     target->set_radius(target_sma);
00060 
00061     sdyn* projectile = target->get_younger_sister();
00062     projectile->set_mass(projectile_mass);
00063     projectile->set_radius(projectile_radius);
00064 
00065     // Establish the orbital elements of the scattering:
00066 
00067     v_inf *= sqrt(0.5*m_total);
00068     // Exactly one of rho_sq_max and peri should be < 0.
00069 
00070     if (rho_sq_max*peri > 0) err_exit("Inconsistent initial conditions.");
00071 
00072     if(rho_sq_min<0)
00073       rho_sq_min = 0;
00074     
00075     real rho_max = -1;
00076     if(rho_sq_max>0)
00077       rho_max = sqrt(rho_sq_max);
00078     //    PRL(v_inf);
00079     //    PRL(peri);
00080 
00081     if (peri > 0) {
00082         if (v_inf > 0)
00083             rho_max = peri * sqrt(1 + 2*m_total/(peri*v_inf*v_inf));
00084         else
00085             rho_max = peri;
00086     }
00087     // Adjusted by (SPZ: 11 Oct 2000)
00088     // randomize rho \propto \sqrt{rho_max^2}
00089     //    PRL(rho_sq_min);PRL(rho_max);
00090     real rho = sqrt(randinter(rho_sq_min, pow(rho_max, 2)));
00091     //    PRL(rho);
00092 
00093     // Note: Unit of velocity is v_g, not v_crit (identical for equal masses)
00094 
00095     real energy = .5 * v_inf * v_inf;
00096     real ang_mom = rho * v_inf;
00097 
00098     //    PRC(energy);PRC(ang_mom);PRC(v_inf);PRL(rho);
00099     //    PRL(ang_mom);
00100  
00101     real ecc = (energy == 0 ? 1 : sqrt( 1 + 2 * energy
00102                                               * pow(ang_mom/m_total, 2)));
00103 
00104     // Special case: if v_inf = 0, assume rho is periastron.
00105 
00106     real virial_ratio = rho;
00107 
00108     kepler k;
00109 
00110     // Don't use mean_anomaly = 0 here (see scatter3.C):
00111 
00112     //PRC(m_total);PRC(energy);PRC(ecc);PRL(virial_ratio);
00113     make_standard_kepler(k, 0, m_total, energy, ecc, virial_ratio, -0.001, 1);
00114 
00115     // Radius for "unperturbed" inner binary:
00116 
00117     real r_unp = (target_sma + projectile_radius)
00118                      * pow(TIDAL_TOL_FACTOR / m_total, -1/3.0);
00119 
00120     real r_start = min(r_init, r_unp);
00121     if (k.get_separation() < r_start)
00122         k.return_to_radius(r_start);
00123     else
00124         k.advance_to_radius(r_start);
00125 
00126     // Initialize the dynamics.
00127 
00128     root->set_time(k.get_time());
00129     target->set_time(k.get_time());
00130     projectile->set_time(k.get_time());
00131     
00132     target->set_pos(-projectile_mass * k.get_rel_pos() / m_total);
00133     target->set_vel(-projectile_mass * k.get_rel_vel() / m_total);
00134 
00135     projectile->set_pos(target_mass * k.get_rel_pos() / m_total);
00136     projectile->set_vel(target_mass * k.get_rel_vel() / m_total);
00137 
00138 //    cerr << "Initialized root...\n";
00139 //    pp(root, cerr);
00140 
00141 //    cerr << "t: " << target->get_index()
00142 //       <<" " << target->get_name() << endl;
00143 //    cerr << "p: " << projectile->get_index()
00144 //       << " "   << projectile->get_name() << endl;
00145 }
00146 
00147 // split_particle: Split the specified node into a binary with the specified
00148 //                 parameters.  All unspecified orbit elements are chosen
00149 //                 randomly.  Newly created nodes have names "n1" and "n2",
00150 //                 where "n" is the name of the node being split.
00151 
00152 local void split_particle(sdyn* current, real ecc, real sma, int planar,
00153                           real mass_ratio, real r1, real r2) {
00154 
00155     if (current->get_oldest_daughter() != NULL)
00156         err_exit("Can't split a binary node!");
00157 
00158     // Update the binary tree structure:
00159 
00160     sdyn* d1 = new sdyn;
00161     sdyn* d2 = new sdyn;
00162 
00163     current->set_oldest_daughter(d1);
00164 
00165     d1->set_parent(current);
00166     d2->set_parent(current);
00167 
00168     d1->set_younger_sister(d2);
00169     d2->set_elder_sister(d1);
00170 
00171     // Set new masses and radii:
00172 
00173     real m_total = current->get_mass();
00174     real m1 = m_total / (1 + mass_ratio);
00175     real m2 = m1 * mass_ratio;
00176 
00177     // By convention, first component has larger mass.
00178 
00179     if (m1 < m2) {
00180         real temp = m1;
00181         m1 = m2;
00182         m2 = temp;
00183     }
00184 
00185     d1->set_mass(m1);
00186     d2->set_mass(m2);
00187     
00188     //    PRC(m1);PRC(r1);PRC(m2);PRL(r2);
00189     d1->set_radius(r1);
00190     d2->set_radius(r2);
00191     
00192     // Sets parent radius (center of mass) to zero
00193     d2->get_parent()->set_radius(0);
00194 
00195     // Set internal orbital elements:
00196 
00197     kepler k;
00198 
00199     if (sma < 0) {
00200         sma = DEFAULT_SMA;
00201         for (int i = 1; i < strlen(current->get_name()); i++)
00202             sma /= SMA_REDUCE;
00203     }
00204 
00205     if (ecc < 0 || ecc >= 1) {
00206 
00207       // factor 2 for MIN_PERI_FACTOR see sdyn/util/make_tree.C
00208       real peri_min = 2*max(d1->get_radius(), d2->get_radius());
00209       real e_max = 1 - peri_min/sma;
00210 
00211       if(e_max<0) 
00212         err_exit("initial eccentricity out of bounds in split_particle(...)"); 
00213 
00214       // Thermal distribution in eccentricity
00215       if(STABILITY)
00216         ecc = sqrt(randinter(0, e_max*e_max));  
00217       else
00218         ecc = sqrt(randinter(0,1));     
00219     }
00220 
00221     //    cerr << "Splitting " << current->get_name();
00222     //    cerr << ",  planar flag = " << planar << endl;
00223     //    cerr << "ecc, sma = " << ecc << " " << sma << endl;
00224 
00225     real peri = 1; // Default value (unimportant unless ecc = 1).
00226     if (ecc == 1) peri = 0;
00227 
00228     // For now, binary phase is random.
00229 
00230     real mean_anomaly = randinter(-PI, PI);
00231 
00232     make_standard_kepler(k, 0, m_total, -0.5 * m_total / sma, ecc,
00233                          peri, mean_anomaly);
00234 
00235     set_random_orientation(k, planar);
00236 
00237     d1->set_time(current->get_time());
00238     d2->set_time(current->get_time());
00239 
00240     d1->set_pos(-m2 * k.get_rel_pos() / m_total);
00241     d1->set_vel(-m2 * k.get_rel_vel() / m_total);
00242 
00243     d2->set_pos(m1 * k.get_rel_pos() / m_total);
00244     d2->set_vel(m1 * k.get_rel_vel() / m_total);
00245 
00246     // Naming convention:
00247 
00248     d1->set_name(current->get_name());
00249     d2->set_name(current->get_name());
00250     strcat(d1->get_name(), "1");
00251     strcat(d2->get_name(), "2");
00252 
00253 //    cerr << "Pretty-print " << current->get_name() << endl;
00254 //    pp(current, cerr);
00255 }
00256 
00257 // locate_label_and_set_defaults: Return a pointer to the node with the
00258 //                                specified name, creating the binary tree
00259 //                                above it if necessary and establishing
00260 //                                default parameters at each level.
00261 
00262 // Note that the node name is strictly defined and the number of characters in
00263 // the name is the level in the binary tree: "t", "t1", "t11", "t112", etc.
00264 
00265 #include <string.h>
00266 local sdyn* locate_label_and_set_defaults(sdyn* root, char* label, int planar) {
00267 
00268     sdyn* b = root;
00269 
00270     for (int i = 0; i < strlen(label); i++) {
00271 
00272         char* name = strdup(label);
00273         name[i+1] = '\0';               // Truncate name to current level
00274 
00275         sdyn* node = NULL;
00276 
00277 //      cerr << "Looking for " << name<<endl;
00278 
00279         while (node == NULL) {
00280             for_all_daughters(sdyn, b, bb)
00281                 if (strcmp(bb->get_name(), name) == 0) node = bb;
00282             if (node == NULL) {
00283                 if (b->get_oldest_daughter() != NULL) return NULL;
00284 
00285 //              cerr << "Not found, making default daughters\n";
00286 
00287                 split_particle(b, DEFAULT_ECC, -1, planar,
00288                                DEFAULT_MASS_RATIO, DEFAULT_R1, DEFAULT_R2);
00289             } 
00290 //          else
00291 //              cerr << "Found " << node->get_name()<<endl;
00292         }
00293         b = node;
00294     }
00295     return b;
00296 }
00297 
00298 // first_leaf: return a pointer to the first leaf descended from the
00299 //             specified node.
00300 
00301 sdyn* first_leaf(sdyn* b)
00302 {
00303     while (b->get_oldest_daughter()) b = b->get_oldest_daughter();
00304     return b;
00305 }
00306 
00307 // next_leaf: return a pointer to the next leaf after the present node.
00308 
00309 sdyn* next_leaf(sdyn* b)
00310 {
00311     if (b == NULL)
00312 
00313         return NULL;
00314 
00315     else if (b->get_oldest_daughter())
00316 
00317         return first_leaf(b);
00318 
00319     else // Ascend the tree looking for a younger sister.
00320 
00321         while (b != NULL && b->get_younger_sister() == NULL)
00322             b = b->get_parent();
00323 
00324     return (b == NULL ? (sdyn*)NULL : first_leaf(b->get_younger_sister()));
00325 }
00326 
00327 sdyn* mkscat(int argc, char **argv, sigma_input &input) {
00328 
00329     // Establish standard configuration and names:
00330 
00331     sdyn* root = mksdyn(2);     // Top-level (unbound) scattering orbit.
00332     root->set_name("r");
00333     root->set_index(-1);        // Undo indexing effect of mksdyn...
00334 
00335     sdyn* target = root->get_oldest_daughter();
00336     target->set_name("t");
00337     target->set_index(-1);
00338 
00339     sdyn* projectile = target->get_younger_sister();
00340     projectile->set_name("p");
00341     projectile->set_index(-1);
00342 
00343     sdyn* current = root;       // Node currently under consideration.
00344 
00345     // Establish defaults for the top level:
00346 
00347     real projectile_mass = 1;   // Note convention: projectile and target have
00348     real projectile_radius = 0; //                  EQUAL masses by default.
00349     real v_inf = 1;
00350     real rho = 0;
00351     real peri = -1;
00352     real initial_separation = VERY_LARGE_NUMBER;
00353 
00354     real mass_ratio = DEFAULT_MASS_RATIO;   // Parameters to use when the
00355     real ecc = DEFAULT_ECC;                 // next binary is built
00356     real sma = DEFAULT_SMA;
00357     real r1 = DEFAULT_R1;
00358     real r2 = DEFAULT_R2;
00359 
00360     int  planar = 0;
00361     bool debug = FALSE;
00362 
00363     // First scan the argument list to get the actual random seed used:
00364 
00365     int  seed = 0;
00366     int i = 0;
00367     int random_seed;
00368     while (++i < argc)
00369         if (argv[i][0] == '-' && argv[i][1] == 's') {
00370           seed = atoi(argv[++i]);
00371           if(seed!=0) 
00372             random_seed = srandinter(seed);
00373           else
00374             cerr << "Seed not re-initialized" << endl;
00375           seed = -1;
00376         }
00377     if(seed>0) 
00378       random_seed = srandinter(seed);
00379 
00380     // Now parse the rest of the command line and initialize the system.
00381 
00382     i = 0;
00383     while (++i < argc) if (argv[i][0] == '-')
00384         switch (argv[i][1]) {
00385 
00386             // Top-level parameters:
00387 
00388             case 'M': if (current != root) cerr <<
00389                         "Too late to initialize projectile mass!\n";
00390                       projectile_mass = atof(argv[++i]);
00391                       input.pmass = projectile_mass;
00392                       break;
00393             case 'R': projectile_radius = atof(argv[++i]);
00394                       break;
00395             case 'r': switch(argv[i][2]) {
00396                           case '\0':    if (current != root) cerr <<
00397                               "Too late to initialize impact parameter!\n";
00398                                         if(input.rho_sq_max<0 && input.peri<0) {
00399                                           rho = atof(argv[++i]);
00400                                           peri = -1;
00401                                           input.rho_sq_max = rho*rho;
00402                                           input.peri = -1;
00403                                         }
00404                                         break;
00405                           case 'm':    if (current != root) cerr <<
00406                               "Too late to initialize pericenter!\n";
00407                                         if(input.rho_sq_max<0 && input.peri<0) {
00408                                           peri = atof(argv[++i]);
00409                                           rho = -1;
00410                                           input.peri = peri;
00411                                           input.rho_sq_max = rho;
00412                                         }
00413                                         break;
00414                           case '1':     r1 = atof(argv[++i]);
00415                                         break;
00416                           case '2':     r2 = atof(argv[++i]);
00417                                         break;
00418                           default:      cerr << "Incorrect 'r' flag ignored\n";
00419                                         break;
00420                       }
00421                       break;
00422             case 'S': initial_separation = atof(argv[++i]);
00423                       break;
00424             case 'v': if (current != root) cerr <<
00425                         "Too late to initialize velocity at infinity!\n";
00426                       if(input.rho_sq_max<0 && input.peri<0) {
00427                         v_inf = atof(argv[++i]);
00428                         input.v_inf = v_inf;
00429                       }
00430                       break;
00431 
00432             // Begin accumulating parameters on a new node:
00433 
00434             case 'p':
00435             case 't': if (current == root)
00436                           initialize_root(root, input.v_inf, 
00437                                           input.rho_sq_min, input.rho_sq_max, 
00438                                           input.peri,
00439                                           initial_separation,
00440                                           projectile_mass, projectile_radius);
00441                       else
00442                           split_particle(current, ecc, sma, planar,
00443                                          mass_ratio, r1, r2);
00444 
00445                       current = locate_label_and_set_defaults(root,
00446                                                               &argv[i][1],
00447                                                               planar);
00448                       if (current == NULL) err_exit("Illegal node name.");
00449 
00450                       // Reset the defaults (note that planar isn't reset):
00451 
00452                       mass_ratio = DEFAULT_MASS_RATIO;
00453                       //                      ecc = DEFAULT_ECC;
00454                       //ecc = sqrt(randinter(0, 1));
00455                       ecc = -1;
00456                       sma = -1;         // Impossible value
00457                       r1 = DEFAULT_R1;
00458                       r2 = DEFAULT_R2;
00459 
00460                       break;
00461 
00462             // Binary parameters:
00463 
00464             case 'a': sma = atof(argv[++i]);
00465                       break;
00466             case 'e': ecc = atof(argv[++i]);
00467                       break;
00468             case 'q': mass_ratio = atof(argv[++i]);
00469                       break;
00470 
00471             case 'P': switch(argv[i][2]) {
00472                           case '-':     planar = -1;
00473                                         break;
00474                           case '0':     planar = 0;
00475                                         break;
00476                           case '+':     planar = 1;
00477                                         break;
00478                           case '\0':    if (planar == 0)
00479                                             planar = 1;
00480                                         else
00481                                           planar = 0;
00482                                         break;
00483                           default:      cerr << "Incorrect 'P' flag ignored\n";
00484                                         break;
00485                       }
00486                         break;
00487 
00488             case 'd': debug = 1 - debug;
00489                       break;
00490             case 's': break;
00491 
00492             default:  cerr << "usage: mkscat [-d] [-s #]"
00493                            << " [-M #] [-r #] [-rm #] [-v #] [-R #] [-S #]"
00494                            << " [ -t/p... [-a #] [-e #] [-q #] [-P[+/-]"
00495                            << " [-r1 #] [-r2 #] ] [-t/p... ...]"
00496                            << endl;
00497                       exit(1);
00498         }
00499 
00500     // Initialize the last piece:
00501 
00502     if (current == root)
00503         initialize_root(root, input.v_inf, input.rho_sq_min, input.rho_sq_max, 
00504                         input.peri, 
00505                         initial_separation,
00506                         projectile_mass, projectile_radius);
00507     else
00508         split_particle(current, ecc, sma, planar,
00509                        mass_ratio, r1, r2);
00510 
00511     // Finally, assign sequential indices to the particles, for the
00512     // convenience of xstarplot and other display/reduction programs.
00513 
00514     int id = 0;
00515     sdyn* b = first_leaf(root);
00516     while (b) {
00517         b->set_index(++id);
00518         b = next_leaf(b);
00519     }
00520 
00521 //----------------------------------------------------------------------------
00522 
00523     root->log_history(argc, argv);
00524 
00525     char seedlog[80];
00526     sprintf(seedlog, "           random seed = %d",
00527             random_seed);
00528     root->log_comment(seedlog);
00529 
00530     if (0) {
00531         cerr << "mkscat: pretty-print system (seed = "
00532              << random_seed << "):\n";
00533         pp(root, cerr);
00534     }
00535 
00536     return root;
00537 }
00538 
00539 #define MAX_ARGS 256
00540 #define TEXT_BUFFER_SIZE 1024
00541 
00542 static char temp[TEXT_BUFFER_SIZE];     // argv will point into this array
00543 static char* name = "parse_string";     // Any name will do...
00544 
00545 // parse_string: Split a character string into words.  Return a list of
00546 //               substrings, using the same conventions as argc and argv
00547 //               in UNIX (0 --> "parse_string").
00548 
00549 void parse_string(char* s, int& argc, char* argv[]) {
00550 
00551     int length = strlen(s);
00552     if (length >= TEXT_BUFFER_SIZE) err_exit("String too long.");
00553 
00554     argv[0] = name;
00555     argc = 1;
00556 
00557     int first = 0, last = -1;  // First and last characters of the current word
00558 
00559     for (int i = 0; i <= length; i++) {
00560         temp[i] = s[i];
00561         if (temp[i] == ' ' || i == length) {
00562             if (last >= 0) {                            // End of word
00563                 temp[i] = '\0';
00564                 argv[argc++] = temp + first;            // *No* check on argc
00565             }
00566             last = -1;
00567         } else {
00568             if (last < 0) first = i;                    // Start of word
00569             last = i;
00570         }
00571     }
00572 }
00573 
00574 
00575 sdyn* mkscat(char* s, sigma_input &input) {     
00576                                     // Character string interface to mkscat
00577     int argc;
00578     char* argv[MAX_ARGS];
00579 
00580     parse_string(s, argc, argv);
00581     if (argc > MAX_ARGS) err_exit("Too many arguments.");
00582 
00583     return mkscat(argc, argv, input);
00584 }    
00585 
00586 #endif

Generated at Sun Feb 24 09:57:09 2002 for STARLAB by doxygen1.2.6 written by Dimitri van Heesch, © 1997-2001