Newer
Older
#ifdef USE_KIRA
#include "worldline.h"
// #define CAVE 1 // NewN: use potentially-shared-memory malloc
#include "shmem.h"
#include "specks.h"
#include "partiviewc.h"
#include "kira_parti.h" // declare following as extern "C"
extern struct specklist *kira_get_parti( struct stuff *st, double realtime );
int ih; // current worldbundle index
real tmin, tmax;
real tcur; // current time
real treq; // requested time
int treearcs; // KIRA_{OFF|ON|CROSS|TICK}
float tickscale; // size of treearc cross mark (frac of sep)
int ringsizer; // KIRA_RINGSEP, KIRA_RINGA
float ringscale; // multiplier for above
float ringmin, ringmax; // range of pixel sizes for ring markers
int tracking, wastracking; // id of particle we're tracking, or zero
Point trackpos; // last known position of tracked particle
int *starset; // per-star bitmask of "sets" it belongs to
struct specklist *trailsl; // per-star specklist of recent history
int maxtrail, ntrail;
struct speck *marksp; // current pointer, updated by add_speck
int leafcount; // temp, used in recursion only
nh = 0;
wh = NULL;
ih = 0;
tmin = 0, tmax = 1;
tcur = treq = 0;
treenodes = KIRA_ON;
treerings = KIRA_OFF;
ringsizer = KIRA_RINGA;
ringscale = 1.5;
ringmin = 2;
ringmax = 50;
marksp = NULL;
leafcount = 0;
}
};
// speck fields:
// [0] worldline index (= kira index for singles, - and unique for others)
// [1] mass
// [2] number in clump
// [3] top-level name
// [4] address in clump
// [5] ring size
// [6] mass ratio (for nonleaves) (mu = child1/(child1+child2))
// [7..9] child separation vector (for nonleaves)
enum speckfields {
SPECK_ID = 0, // worldline index (= kira index for single stars,
// unique small negative int for others)
SPECK_MASS = 1, // mass
SPECK_NCLUMP = 2, // number of stars in clump
SPECK_ROOTID = 3, // worldline index of root of clump
SPECK_TREEADDR = 4, // bit-encoded tree address within our clump (0 for isolated stars)
SPECK_RINGSIZE = 5, // size of ring marker
SPECK_MU = 6, // mass ratio
SPECK_SEPVEC = 7, // separation vector[3]
SPECK_NDATAFIELDS = 10
static char *fieldnames[] = {
"id",
"mass",
"nclump",
"rootid",
"treeaddr",
"ringsize",
"mu",
"sepvec3",
NULL
};
void kira_invalidate( struct stuff *st ) {
if(st->sl) st->sl->used = -1000000;
worldstuff *ww = (worldstuff *)st->dyndatadata;
if(ww) ww->slvalid = 0;
}
int kira_set( struct stuff *st, int what, double val )
{
struct worldstuff *ww = (struct worldstuff *)st->dyndatadata;
if(ww == NULL) return 0;
if(kira_get(st, what) == val)
return 2;
switch(what) {
case KIRA_NODES: ww->treenodes = (int)val; break;
case KIRA_RINGS: ww->treerings = (int)val; break;
case KIRA_TREE: ww->treearcs = (int)val; break;
case KIRA_TICKSCALE: ww->tickscale = val; break;
case KIRA_RINGSIZE: ww->ringsizer = (int)val; break;
case KIRA_RINGSCALE: ww->ringscale = val; break;
case KIRA_RINGMIN: ww->ringmin = val; break;
case KIRA_RINGMAX: ww->ringmax = val; break;
case KIRA_TRACK: if(ww->tracking != (int)val) ww->wastracking = 0;
ww->tracking = (int)val; break;
specks_set_timestep( st );
parti_redraw();
return 1;
}
double kira_get( struct stuff *st, int what )
{
struct worldstuff *ww = (struct worldstuff *)st->dyndatadata;
if(ww == NULL) return 0;
switch(what) {
case KIRA_NODES: return ww->treenodes;
case KIRA_RINGS: return ww->treerings;
case KIRA_TREE: return ww->treearcs;
case KIRA_TICKSCALE: return ww->tickscale;
case KIRA_RINGSIZE: return ww->ringsizer;
case KIRA_RINGSCALE: return ww->ringscale;
case KIRA_RINGMIN: return ww->ringmin;
case KIRA_RINGMAX: return ww->ringmax;
case KIRA_TRACK: return ww->tracking;
int hasdata( ifstream *s, double maxwait ) {
struct timeval tv;
fd_set fds;
if(s == NULL) return 0;
if(s->rdbuf()->in_avail() || s->eof()) return 1;
if(maxwait < 0) maxwait = 0;
tv.tv_sec = (int)maxwait;
tv.tv_usec = (int) (1000000 * (maxwait - tv.tv_sec));
FD_ZERO(&fds);
FD_SET(s->rdbuf()->fd(), &fds);
return(select(s->rdbuf()->fd() + 1, &fds, NULL, NULL, &tv) > 0);
}
int kira_read_more(struct stuff *st, int nmax, double tmax, double realdtmax)
struct worldstuff *ww = (struct worldstuff *)st->dyndatadata;
if(ww == NULL) return -1;
ifstream *ins = ww->ins;
if(ins == NULL || !ins->is_open()) return -1;
int paras = 0;
int timelimit = (realdtmax < 1e6);
double wallstop = realdtmax + wallclock_time();
while( paras < nmax && (ww->nh == 0 || ww->wh[ww->nh-1]->get_t_max() < tmax) ) {
if(timelimit) {
double dt = wallstop - wallclock_time();
if(!hasdata(ins, dt))
break;
if(dt <= 0)
break;
}
if(ww->nh >= ww->maxnh) {
ww->maxnh = (ww->nh > ww->maxnh*2) ? ww->nh + 1 : ww->maxnh*2;
ww->wh = RenewN( ww->wh, worldbundleptr, ww->maxnh );
}
worldbundle *wb;
wb = read_bundle(*ins, ww->readflags & KIRA_VERBOSE);
if(wb == NULL) {
ins->close();
if(paras == 0) paras = -1;
break;
}
paras++;
}
if(paras > 0) {
ww->tmin = ww->wh[0]->get_t_min();
ww->tmax = ww->wh[ww->nh-1]->get_t_max();
}
return paras;
}
int kira_open(struct stuff *st, char *filename, int readflags)
{
ifstream *ins = new ifstream(filename);
if (!ins || !*ins) {
msg("Kira/starlab data file %s not found.", filename);
delete ins;
worldbundle *wb;
struct worldstuff *ww = NewN( worldstuff, 1 ); // from shmem -- avoid "new"
ww->init();
ww->maxnh = 1024;
ww->wh = NewN( worldbundleptr, ww->maxnh );
ww->ins = ins;
ww->tmin = ww->tmax = 0;
ww->nh = 0;
if(! (readflags & KIRA_READLATER)) {
kira_read_more( st, ww->maxnh, 1e38, 1e38 );
if (ww->nh == 0) {
msg("Data file %s not in worldbundle format.", filename);
return 0;
}
}
ww->ih = 0;
ww->sl = NULL;
// If data field names aren't already assigned, set them now.
for(int i = 0; fieldnames[i] != NULL; i++) {
if(st->vdesc[st->curdata][i].name[0] == '\0')
strcpy(st->vdesc[st->curdata][i].name, fieldnames[i]);
}
return 1;
}
double get_parti_time( struct stuff *st ) {
if(st->dyndatadata == NULL)
return 0.0;
return ((struct worldstuff *)(st->dyndatadata))->tcur;
}
void set_parti_time( struct stuff *st, double reqtime ) {
if(st->dyndatadata == NULL)
return;
// otherwise please seek to requested time ...
}
int get_parti_time_range( struct stuff *st, double *tmin, double *tmax )
{
struct worldstuff *ww = (struct worldstuff *)st->dyndatadata;
if(ww == NULL) {
return 0;
}
*tmin = ww->tmin;
*tmax = ww->tmax;
return 1;
}
speck *add_speck(dyn *b, dyn *top, int addr, speck *sp, specklist *sl, worldstuff *ww)
sp->p.x[0] = b->get_pos()[0];
sp->p.x[1] = b->get_pos()[1];
sp->p.x[2] = b->get_pos()[2];
sp->val[SPECK_NCLUMP] = 0; // complete (add n_leaves) in kira_to_parti
dyn *bb = b;
while (bb->get_elder_sister())
bb = bb->get_elder_sister();
if (bb->get_kepler()) sp->val[SPECK_NCLUMP] += 100;
// Addr is 0 for top-level leaf, 1 for top-level CM,
// constructed from parent addr otherwise.
return sp;
}
speck *assign_specks(dyn *b, dyn *top, int addr, speck *sp, specklist *sl, worldstuff *ww)
{
// Convert relative coordinates to absolute.
if (b != top)
b->inc_pos(b->get_parent()->get_pos());
if(ww->tracking != 0 && abs(ww->tracking) == b->get_index()) {
Point newpos;
newpos.x[0] = b->get_pos()[0];
newpos.x[1] = b->get_pos()[1];
newpos.x[2] = b->get_pos()[2];
if(ww->wastracking) {
Point delta;
vsub( &delta, &newpos,&ww->trackpos );
parti_nudge_camera( &delta );
}
ww->trackpos = newpos;
ww->wastracking = 1;
}
if(b->is_leaf()
|| ww->treenodes == KIRA_ON
|| (ww->treenodes == KIRA_ROOTS && b == top)) {
sp = add_speck(b, top, addr, sp, sl, ww);
if(b->is_leaf())
ww->leafcount++;
}
if(!b->is_leaf() &&
|| (ww->treerings == KIRA_ROOTS && b == top))) {
struct speck *marksp = ww->marksp;
ww->marksp = add_speck(b, top, addr, marksp, ww->marksl, ww);
// find our two children
dyn *b1 = b->get_oldest_daughter();
dyn *b2 = b1 ? b1->get_younger_sister() : NULL;
if(b2) {
vector sep = b1->get_pos() - b2->get_pos();
real dist = sqrt(sep * sep);
break;
case KIRA_RINGA:
{
vector vel = b1->get_vel() - b2->get_vel();
real speed2 = vel * vel;
real E = 0.5 * speed2 - mass / dist;
size = -mass / (2*E); // semimajor axis
}
}
marksp->val[SPECK_RINGSIZE] = size * ww->ringscale;
marksp->val[SPECK_MU] = b1->get_mass() / mass;
marksp->val[SPECK_SEPVEC] = sep[0];
marksp->val[SPECK_SEPVEC+1] = sep[1];
marksp->val[SPECK_SEPVEC+2] = sep[2];
struct specklist *kira_to_parti(dyn *root, struct stuff *st, struct specklist *sl)
// Use NewN to allocate these in (potentially) shared memory,
// rather than new which will allocate in local malloc pool.
// Needed for virdir/cave version.
int smax = root->n_leaves();
ww->maxstars = 2*smax;
ww->maxmarks = 1+smax;
sl->bytesperspeck = SMALLSPECKSIZE( SPECK_NDATAFIELDS );
sl->specks = NewNSpeck(sl, ww->maxstars);
marksl = NewN( struct specklist, 1 );
*marksl = *sl;
marksl->specks = NewNSpeck(marksl, ww->maxmarks);
marksl->special = MARKERS;
sl->next = marksl;
marksl->next = NULL;
ww->sl = sl;
ww->marksl = marksl;
int k;
int nleaves = ww->leafcount - nl;
int count = sl->nspecks - ns;
for(k = 0; k < count; k++) {
tsp->val[SPECK_NCLUMP] += nleaves;
if(tsp->val[0] < 0)
tsp->val[SPECK_NCLUMP] = -tsp->val[SPECK_NCLUMP]; // negate nclump for CM nodes
count = marksl->nspecks - mns;
for(k = 0; k < count; k++) {
msp->val[SPECK_NCLUMP] += nleaves;
if(msp->val[0] < 0)
msp->val[SPECK_NCLUMP] = -msp->val[SPECK_NCLUMP]; // negate nclump for CM nodes
msp = NextSpeck(msp, sl, 1);
}
if(ww->wastracking < 0) ww->wastracking = 0; // Detach if tracked pcle not found now
struct specklist *kira_get_parti( struct stuff *st, double realtime )
return NULL;
ww->treq = realtime;
if (realtime < ww->tmin) realtime = ww->tmin;
if (realtime > ww->tmax) realtime = ww->tmax;
return ww->sl;
int ih = ww->ih;
int nh = ww->nh;
worldbundle *wb = ww->wh[ih];
for(; realtime > wb->get_t_max() && ih < nh-1; ih++, wb = ww->wh[ih])
;
for(; realtime < wb->get_t_min() && ih > 0; ih--, wb = ww->wh[ih])
;
dyn *root = create_interpolated_tree(wb, realtime);
void kira_draw( struct stuff *st, struct specklist *slhead, Matrix *Tc2w, float radperpix )
{
struct worldstuff *ww = (struct worldstuff *)st->dyndatadata;
static Point zero = {0,0,0};
Point fwdvec = {0,0,-radperpix}; // scaled by pixels-per-radian
float fwdd;
vtfmpoint( &eyepoint, &zero, Tc2w );
vtfmvector( &fwd, &fwdvec, Tc2w );
fwdd = -vdot( &eyepoint, &fwd );
#define MAXRING 32
Point fan[MAXRING];
int nring = 24;
int i;
for(i = 0; i < nring; i++) {
float th = 2*M_PI*i / nring;
vcomb( &fan[i], cos(th),(Point *)&Tc2w->m[0*4+0],
sin(th),(Point *)&Tc2w->m[1*4+0] );
}
for(sl = slhead; sl != NULL; sl = sl->next) {
if(sl->special == MARKERS) {
int ns = sl->nspecks;
struct speck *sp = sl->specks;
for(i = 0; i < ns; i++, sp = NextSpeck(sp, sl, 1)) {
float unitperpix = vdot( &fwd, &sp->p ) + fwdd;
if(unitperpix <= 0) continue;
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
if(ww->treerings == KIRA_ON ||
(ww->treerings == KIRA_ROOTS && sp->val[SPECK_TREEADDR] == 1)) {
float ringpixels = fabs(sp->val[SPECK_RINGSIZE]) / unitperpix;
if(ringpixels < ww->ringmin) ringpixels = ww->ringmin;
if(ringpixels > ww->ringmax) ringpixels = ww->ringmax;
float rring = ringpixels * unitperpix;
int step = ringpixels>20 ? 1 : ringpixels>8 ? 2 : 3;
glColor3ubv( (GLubyte *)&sp->rgba );
glBegin( GL_LINE_LOOP );
for(int k = 0; k < nring; k+=step)
glVertex3f( sp->p.x[0] + rring*fan[k].x[0],
sp->p.x[1] + rring*fan[k].x[1],
sp->p.x[2] + rring*fan[k].x[2] );
glEnd();
}
if(ww->treearcs != KIRA_OFF) {
float mu = sp->val[SPECK_MU];
float *sep = &sp->val[SPECK_SEPVEC];
glColor3ubv( (GLubyte *)&sp->rgba );
glBegin( GL_LINES );
if(ww->treearcs != KIRA_TICK) {
glVertex3f(
sp->p.x[0] - mu*sep[0],
sp->p.x[1] - mu*sep[1],
sp->p.x[2] - mu*sep[2] );
glVertex3f(
sp->p.x[0] + (1-mu)*sep[0],
sp->p.x[1] + (1-mu)*sep[1],
sp->p.x[2] + (1-mu)*sep[2] );
}
if(ww->treearcs == KIRA_CROSS || ww->treearcs == KIRA_TICK) {
Point cr;
vcross( &cr, &unitfwd, (Point *)sep );
float sepsep = vdot((Point *)sep, (Point *)sep);
float sepfwd = vdot((Point *)sep, &unitfwd);
float scaleby = halftickscale / sqrt(1 - sepfwd*sepfwd/sepsep);
glVertex3f(
sp->p.x[0] - scaleby*cr.x[0],
sp->p.x[1] - scaleby*cr.x[1],
sp->p.x[2] - scaleby*cr.x[2] );
glVertex3f(
sp->p.x[0] + scaleby*cr.x[0],
sp->p.x[1] + scaleby*cr.x[1],
sp->p.x[2] + scaleby*cr.x[2] );
}
glEnd();
}
glPointSize( 1.0 );
glBegin( GL_POINTS );
for(i = 1; i < st->nghosts; i++) {
sl = specks_timespecks( st, st->curdata, i );
if(sl == NULL) continue;
int k, rgba = 0;
struct speck *sp;
for(k = 0, sp = sl->specks; k < sl->nspecks; k++, sp = NextSpeck(sp, sl, 1)) {
if(rgba != sp->rgba) {
glColor3ubv( (GLubyte *)&sp->rgba );
rgba = sp->rgba;
}
glVertex3fv( &sp->p.x[0] );
}
}
glEnd();