00001
00013
00014 #include "dyn.h"
00015
00016 #ifndef TOOLBOX
00017
00018 typedef struct
00019 {
00020 real r2;
00021 dyn *p;
00022 } rp_pair, *rp_pair_ptr;
00023
00024
00025
00026
00027
00028 local int compare_radii(const void * pi, const void * pj)
00029 {
00030 if (((rp_pair_ptr) pi)->r2 > ((rp_pair_ptr) pj)->r2)
00031 return +1;
00032 else if (((rp_pair_ptr)pi)->r2 < ((rp_pair_ptr)pj)->r2)
00033 return -1;
00034 else
00035 return 0;
00036 }
00037
00038 void compute_mcom(dyn *b,
00039 vector& pos, vector& vel,
00040 real f,
00041 int n_iter)
00042 {
00043
00044
00045
00046 if (find_qmatch(b->get_dyn_story(), "mcom_pos")
00047 && getrq(b->get_dyn_story(), "mcom_f") == f
00048 && getrq(b->get_dyn_story(), "mcom_time") == b->get_system_time()) {
00049 pos = getvq(b->get_dyn_story(), "mcom_pos");
00050 vel = getvq(b->get_dyn_story(), "mcom_vel");
00051 return;
00052 }
00053
00054
00055
00056 if (find_qmatch(b->get_dyn_story(), "com_pos")
00057 && getrq(b->get_dyn_story(), "com_time") == b->get_system_time()) {
00058 pos = getvq(b->get_dyn_story(), "com_pos");
00059 vel = getvq(b->get_dyn_story(), "com_vel");
00060 } else
00061 compute_com(b, pos, vel);
00062
00063
00064
00065 int n = 0;
00066 for_all_daughters(dyn, b, bb) n++;
00067 rp_pair *rp = new rp_pair[n];
00068
00069 if (rp == NULL) {
00070 cerr << "compute_mcom: "
00071 << "not enough memory to store rp_pair array\n";
00072 return;
00073 }
00074
00075 bool loop;
00076 int count = n_iter;
00077
00078 if (f > 1) f = 1;
00079 if (f == 1) count = 0;
00080
00081 do {
00082 loop = false;
00083
00084
00085
00086 int i = 0;
00087 for_all_daughters(dyn, b, bi) {
00088 rp[i].r2 = square(bi->get_pos() - pos);
00089 rp[i].p = bi;
00090 i++;
00091 }
00092
00093
00094
00095 qsort((void *)rp, (size_t)i, sizeof(rp_pair), compare_radii);
00096
00097
00098
00099
00100
00101
00102 real r_max2i = 1/rp[(int)(f*n)].r2;
00103 real weighted_mass = 0;
00104 vector new_pos = 0, new_vel = 0;
00105
00106 for (i = 0; i < f*n; i++) {
00107 dyn *bi = rp[i].p;
00108 real weight = bi->get_mass() * max(0.0, 1 - rp[i].r2*r_max2i);
00109 weighted_mass += weight;
00110 new_pos += weight * bi->get_pos();
00111 new_vel += weight * bi->get_vel();
00112 }
00113
00114 if (weighted_mass > 0) {
00115 pos = new_pos / weighted_mass;
00116 vel = new_vel / weighted_mass;
00117 if (count-- > 0) loop = true;
00118 }
00119
00120 } while (loop);
00121
00122 putrq(b->get_dyn_story(), "mcom_time", b->get_system_time());
00123 putvq(b->get_dyn_story(), "mcom_pos", pos);
00124 putvq(b->get_dyn_story(), "mcom_vel", vel);
00125 putrq(b->get_dyn_story(), "mcom_f", f);
00126 putiq(b->get_dyn_story(), "mcom_n_iter", n_iter);
00127 }
00128
00129 void compute_mcom(dyn *b,
00130 real f,
00131 int n_iter)
00132 {
00133 vector pos, vel;
00134 compute_mcom(b, pos, vel, f, n_iter);
00135 }
00136
00137 #else
00138
00139
00140
00141
00142
00143 main(int argc, char ** argv)
00144 {
00145 char *comment;
00146 dyn * b;
00147 bool c_flag = FALSE;
00148
00149 check_help();
00150
00151 extern char *poptarg;
00152 int c;
00153 real f = 0.9;
00154 char* param_string = "c:f:";
00155
00156 while ((c = pgetopt(argc, argv, param_string)) != -1)
00157 switch(c) {
00158
00159 case 'c': c_flag = TRUE;
00160 comment = poptarg;
00161 break;
00162 case 'f': f = atof(poptarg);
00163 break;
00164 case '?': params_to_usage(cerr, argv[0], param_string);
00165 get_help();
00166 exit(1);
00167 }
00168
00169 if ((b = get_dyn(cin)) == NULL)
00170 err_exit("compute_mcom: No N-body system on standard input");
00171
00172 while (b) {
00173
00174 if (c_flag == TRUE)
00175 b->log_comment(comment);
00176 b->log_history(argc, argv);
00177
00178 compute_mcom(b, f);
00179
00180
00181
00182 put_dyn(cout, *b);
00183 rmtree(b);
00184 b = get_dyn(cin);
00185 }
00186 }
00187
00188 #endif
00189
00190