/* Rotate viewport as V' = R*V but letting the anchor stay at the same place */ void rotate (int iw, double R[3][3]) { double V0[3][3], s[3], tmp[3]; if (n[iw].anchor >= 0) { V3SUB (B->BALL[n[iw].anchor].x, AX_3D[iw].x, tmp); M3mV3 (AX_3D[iw].V, tmp, s); } else { V3SUB (n[iw].hook, AX_3D[iw].x, tmp); M3mV3 (AX_3D[iw].V, tmp, s); } M3EQV (AX_3D[iw].V, V0); V3mM3 (R[0], V0, AX_3D[iw].V[0]); V3mM3 (R[1], V0, AX_3D[iw].V[1]); V3NORMALIZE (AX_3D[iw].V[1], tmp[0]); /* ensure the orthogonality numerically */ V3CROSS (AX_3D[iw].V[0], AX_3D[iw].V[1], AX_3D[iw].V[2]); V3NORMALIZE (AX_3D[iw].V[2], tmp[0]); V3CROSS (AX_3D[iw].V[1], AX_3D[iw].V[2], AX_3D[iw].V[0]); if (n[iw].anchor >= 0) { V3mM3 (s, AX_3D[iw].V, tmp); V3SUB (B->BALL[n[iw].anchor].x, tmp, AX_3D[iw].x); } else { V3mM3 (s, AX_3D[iw].V, tmp); V3SUB (n[iw].hook, tmp, AX_3D[iw].x); } return; } /* end rotate() */
void bond_xtal_origin_update (int iw) { register int i,j; int k; double *new_s, ds[3], tmp[3]; if (temporary_disable_bond) return; MALLOC( bond_xtal_origin_update, new_s, DIMENSION*np, double ); V3mM3 (n[iw].xtal_origin, HI, ds); V3TRIM (ds, ds); for (i=0; i<np; i++) { V3SUB ( &(s[DIMENSION*i]), ds, &(new_s[DIMENSION*i]) ); V3TriM ( &(new_s[DIMENSION*i]) ); } if (n[iw].bond_mode == BOND_MODE_USER) for (k=0; k<C->n_cylinders; k++) { i = CylinderAtoms[2*k]; j = CylinderAtoms[2*k+1]; V3SUB (&(new_s[DIMENSION*j]), &(new_s[DIMENSION*i]), tmp); if ( V3NEED_IMAGE(tmp) ) { /* g<0 means geometric invisibility */ C->CYLINDER[k].g = -fabs(C->CYLINDER[k].g); C->CYLINDER[k].radius = -fabs(C->CYLINDER[k].radius); } else { C->CYLINDER[k].g = fabs(C->CYLINDER[k].g); C->CYLINDER[k].radius = fabs(C->CYLINDER[k].radius); V3EQV (B->BALL[i].x, C->CYLINDER[k].x0); } } else for (i=0; i<np; i++) for (j=N->idx[i]; j<N->idx[i+1]; j++) { V3SUB (&(new_s[DIMENSION*N->list[j]]), &(new_s[DIMENSION*i]), tmp); if ( V3NEED_IMAGE(tmp) ) { /* g<0 means geometric invisibility */ C->CYLINDER[j].g = -fabs(C->CYLINDER[j].g); C->CYLINDER[j].radius = -fabs(C->CYLINDER[j].radius); } else { C->CYLINDER[j].g = BOND_G(i, N->list[j]); V3EQV (B->BALL[i].x, C->CYLINDER[j].x0); if (C->CYLINDER[j].r >= 0) C->CYLINDER[j].radius = n[iw].bond_radius; } } free (new_s); n[iw].bond_xtal_origin_need_update = FALSE; return; } /* end bond_xtal_origin_update() */
/* use pointer device to translate the viewport */ bool pointer_translate (int iw, int to_x, int to_y) { double z, tmp[3]; if (n[iw].anchor >= 0) V3SUB (B->BALL[n[iw].anchor].x, AX_3D[iw].x, tmp); else V3SUB (n[iw].hook, AX_3D[iw].x, tmp); z = V3DOT (AX_3D[iw].V[2], tmp); tmp[0] = (n[iw].lx - to_x) / AX_3D[iw].k * z; V3ADDmuL (tmp[0], AX_3D[iw].V[0], AX_3D[iw].x); tmp[1] = (n[iw].ly - to_y) / AX_3D[iw].k * z; V3ADDmuL (tmp[1], AX_3D[iw].V[1], AX_3D[iw].x); n[iw].lx = to_x; n[iw].ly = to_y; return (TRUE); } /* end pointer_translate() */
void p3dp_atom_pair_s(double *sj, double *si, double dxji[4]) { double ds[3]; V3SUB (sj, si, ds); V3ImagE (ds); V3M3LENGTH2 (ds, H, dxji); return; }
/* delta >=0, d -> d/(1+delta), else d -> d * (1-delta). */ bool foo_advance (int iw, double delta) { double tmp[3]; if (delta >= 0) delta = 1/(1+delta); else delta = (1-delta); if (n[iw].anchor >= 0) { V3SUB (AX_3D[iw].x, B->BALL[n[iw].anchor].x, tmp); V3ADDMUL (B->BALL[n[iw].anchor].x, delta, tmp, AX_3D[iw].x); } else { V3SUB (AX_3D[iw].x, n[iw].hook, tmp); V3ADDMUL (n[iw].hook, delta, tmp, AX_3D[iw].x); } return (TRUE); } /* end advance() */
/* calculate dxji[]=x_j[]-x_i[] and |dxji|^2 */ void atom_pair (int j, int i, double dxji[4]) { double ds[3]; V3SUB (&s[DIMENSION*j], &s[DIMENSION*i], ds); V3ImagE (ds); V3M3LENGTH2 (ds, H, dxji); return; } /* end atom_pair() */
bool pointer_advance (int iw, int to_x, int to_y) { double delta, tmp[3]; if (n[iw].ly == to_y) return (FALSE); delta = exp(2*(n[iw].ly-to_y)/n[iw].mgs_radius); if (n[iw].anchor >= 0) { V3SUB (AX_3D[iw].x, B->BALL[n[iw].anchor].x, tmp); V3ADDMUL (B->BALL[n[iw].anchor].x, delta, tmp, AX_3D[iw].x); } else { V3SUB (AX_3D[iw].x, n[iw].hook, tmp); V3ADDMUL (n[iw].hook, delta, tmp, AX_3D[iw].x); } n[iw].lx = to_x; n[iw].ly = to_y; return (TRUE); } /* end pointer_advance() */
void atom_xtal_origin (double xtal_origin[3]) { register int i; double ds[3], new_s[3]; V3mM3 (xtal_origin, HI, ds); V3TRIM (ds, ds); for (i=0; i<np; i++) { V3SUB ( &(s[DIMENSION*i]), ds, new_s ); V3TriM ( new_s ); V3mM3 ( new_s, H, B->BALL[i].x ); } return; } /* end atom_xtal_origin() */
/* use pointer device to shift the crystal */ bool pointer_grab_xtal_shift (int iw, int to_x, int to_y) { double z, tmp[3]; if (!n[iw].xtal_mode) { printf ("Crystal translation is only available under Xtal mode.\n"); return(FALSE); } if ((n[iw].lx == to_x) && (n[iw].ly == to_y)) return (FALSE); if (n[iw].anchor >= 0) V3SUB (B->BALL[n[iw].anchor].x, AX_3D[iw].x, tmp); else V3SUB (n[iw].hook, AX_3D[iw].x, tmp); z = V3DOT (AX_3D[iw].V[2], tmp); tmp[0] = (n[iw].lx - to_x) / AX_3D[iw].k * z; V3ADDmuL (tmp[0], AX_3D[iw].V[0], n[iw].xtal_origin); tmp[1] = (n[iw].ly - to_y) / AX_3D[iw].k * z; V3ADDmuL (tmp[1], AX_3D[iw].V[1], n[iw].xtal_origin); n[iw].lx = to_x; n[iw].ly = to_y; atom_xtal_origin (n[iw].xtal_origin); if (n[iw].bond_mode) bond_xtal_origin_update (iw); else n[iw].bond_xtal_origin_need_update = TRUE; return (TRUE); } /* end pointer_grab_xtal_shift() */
/* Return z>0 if there is intersection, -1 otherwise. */ double Eyesight_Intersect_H_Surface (double H[3][3], int surface_id, double x0[3], double V[3][3], double k0, double k1, double s[3], double x[3]) { int i; double b[3], M[3][3], MI[3][3], tmp; i = surface_id / 2; if (surface_id % 2) V3SUB(x0,H[i],b); else V3EQV(x0,b); M3EQV(H,M); V3NEG(V[2],M[i]); V3SUBmuL(M[i],k0,V[0]); V3SUBmuL(M[i],k1,V[1]); tmp = M3DETERMINANT(M); if (ISTINY(tmp)) return(-1); M3INV(M,MI,tmp); V3mM3(b,MI,s); tmp = s[i]; s[i] = surface_id % 2; V3mM3 (s,H,x); return (tmp); } /* end Eyesight_Intersect_H_Surface() */
/* Allocate bonds */ void Config_to_3D_Bonds (double bond_radius) { register int i,j; AX_Float ds[3], DS[3]; AX_3D_Cylinders_Realloc (C, N->idx[np]); for (i=0; i<np; i++) for (j=N->idx[i]; j<N->idx[i+1]; j++) { V3EQV ( B->BALL[i].x, C->CYLINDER[j].x0 ); V3SUB ( &s[DIMENSION*N->list[j]], &s[DIMENSION*i], ds ); V3IMAGE ( ds, DS ); V3mM3 ( DS, H, C->CYLINDER[j].axis ); AX_V3NORMALIZE ( C->CYLINDER[j].axis, C->CYLINDER[j].axis[3] ); BONDCOLOR (i, N->list[j], j); if (V3NEED_IMAGE(ds)) { C->CYLINDER[j].g = -1; C->CYLINDER[j].radius = -1; } else C->CYLINDER[j].radius = bond_radius; } return; } /* end Config_to_3D_Bonds() */
static int tag_atoms_in_monoclinic_filter (V3 origin, M3 HH, double height, double xytolerance, int *selected, char *taglist) { register int i; M3 HHH, HHHI; double dx[4], ds[3]; M3EQV (HH, HHH); V3MuL (height, HHH[2]); M3inv (HHH, HHHI); selected[0] = 0; selected[1] = 0; for (i=np; i--;) { V3SUB (B->BALL[i].x, origin, dx); V3mM3 (dx, HHHI, ds); if ( XIN(ds[0],-xytolerance,1+xytolerance) && XIN(ds[1],-xytolerance,1+xytolerance) && XIN(ds[2],-0.5,0.5) ) { if (ds[2] < 0) { selected[0]++; taglist[i] = 1; } else { selected[1]++; taglist[i] = 2; } } else taglist[i] = 0; } return(selected[0]+selected[1]); } /* end tag_atoms_in_monoclinic_filter() */
/* Save atoms selected in a monoclinic filter to a file */ void save_atoms_in_monoclinic_filter (int iw) { M3 HH; double d0, zmargin, xytolerance, origin[3]; char danswer[MAX_FILENAME_SIZE], *answer, fname[MAX_FILENAME_SIZE]; char *taglist = NULL; int selected[2]; V3SUB( B->BALL[n[iw].atom_stack[0]].x, B->BALL[n[iw].atom_stack[1]].x, HH[0] ); V3SUB( B->BALL[n[iw].atom_stack[2]].x, B->BALL[n[iw].atom_stack[1]].x, HH[1] ); V3CROSS (HH[0], HH[1], HH[2]); if (V3ISSMALL(HH[2])) { printf("The selected parallelogram is ill-conditioned\n" "for constructing a monoclinic filter.\n"); return; } V3NORMALIZE (HH[2], d0); printf ("\"up\" is [%g %g %g]\n" "check it agrees with your mirror normal...\n", V3E(HH[2])); d0 = 2.5; zmargin = 0.01; xytolerance = 0.01; xterm_get_focus(iw); clear_stdin_buffer(); REALLOC (save_atoms_in_monoclinic_filter, taglist, np, char); while (1) { sprintf (danswer, "%g %g %g", d0, zmargin, xytolerance); answer = readline_gets ("Interplanar spacing [A] z-margin [A] xy-tolerance", danswer); sscanf(answer, "%lf %lf %lf", &d0, &zmargin, &xytolerance); V3ADDMUL (B->BALL[n[iw].atom_stack[1]].x, d0/2,HH[2], origin); if (tag_atoms_in_monoclinic_filter (origin,HH, d0+2*zmargin,xytolerance, selected,taglist)>0) break; strcpy (danswer, answer); } printf("down=%d and up=%d atoms selected in filter.\n", selected[0], selected[1]); while (1) { sprintf (danswer, "%s.idx", fbasename); answer = readline_gets("Save the selected atoms to", danswer); sscanf(answer, "%s", fname); if ( tested_to_be_writable(fname) ) { save_dipole_indices (selected, taglist, fname); printf ("selected atom indices [0-%d] saved to %s.\n", np-1,fname); Free (taglist); break; } else { printf ("\n** %s: **\n", fname); printf ("** This file is unwritable! **\n"); } strcpy(danswer, answer); } xterm_release_focus(iw); return; } /* end save_atoms_in_monoclinic_filter() */
/* Allocate arrows */ void Config_to_3D_Arrows(int arrow_idx, double scale_factor, double head_height, double head_width, double up[3], int overlay, double color[3]) { register int i, j, offset; double dx[3], head[3], head1[3], perp[3], perp2[3], sum; AX_3D_Lines tmp_arrows[1] = {{0}}; tmp_arrows[0].LINE = NULL; if (overlay) { offset = arrows->n_lines; if (offset != 0) { AX_3D_Lines_Realloc(tmp_arrows, arrows->n_lines); for (i=0; i<arrows->n_lines; i++) { V3EQV(arrows->LINE[i].x0, tmp_arrows->LINE[i].x0); V3EQV(arrows->LINE[i].x1, tmp_arrows->LINE[i].x1); AX_3D_AssignRGB (tmp_arrows->LINE[i], arrows->LINE[i].r, arrows->LINE[i].g, arrows->LINE[i].b); } } AX_3D_Lines_Realloc(arrows, arrows->n_lines + 3*np); if (offset != 0) { for (i=0; i<tmp_arrows->n_lines; i++) { V3EQV(tmp_arrows->LINE[i].x0, arrows->LINE[i].x0); V3EQV(tmp_arrows->LINE[i].x1, arrows->LINE[i].x1); AX_3D_AssignRGB (arrows->LINE[i], tmp_arrows->LINE[i].r, tmp_arrows->LINE[i].g, tmp_arrows->LINE[i].b); } AX_3D_Lines_Free(tmp_arrows); } } else { AX_3D_Lines_Realloc(arrows, 3*np); offset = 0; } /* auto scale */ if (scale_factor == 0.0) { sum = 0.0; for (i=0; i<np; i++) { dx[0] = *(CONFIG_auxiliary[arrow_idx+0]+i); dx[1] = *(CONFIG_auxiliary[arrow_idx+1]+i); dx[2] = *(CONFIG_auxiliary[arrow_idx+2]+i); sum += V3LENGTH(dx); } scale_factor = 1.0/(sum/np); printf("Config_to_3D_Arrows: average magnitude = %f, scale_factor set to %f\n", 1.0/scale_factor, scale_factor); } printf("Config_to_3D_Arrows: color = <%.3f,%.3f,%.3f>\n", color[0], color[1], color[2]); for (i=0; i<np; i++) { AX_3D_AssignRGB (arrows->LINE[offset+3*i], color[0], color[1], color[2]); AX_3D_AssignRGB (arrows->LINE[offset+3*i+1], color[0], color[1], color[2]); AX_3D_AssignRGB (arrows->LINE[offset+3*i+2], color[0], color[1], color[2]); dx[0] = *(CONFIG_auxiliary[arrow_idx+0]+i)*scale_factor; dx[1] = *(CONFIG_auxiliary[arrow_idx+1]+i)*scale_factor; dx[2] = *(CONFIG_auxiliary[arrow_idx+2]+i)*scale_factor; if (V3EQZERO(dx)) { for (j=0; j<3; j++) { V3EQV(B->BALL[i].x, arrows->LINE[offset+3*i+j].x0); V3EQV(B->BALL[i].x, arrows->LINE[offset+3*i+j].x1); } } else { V3ADD(B->BALL[i].x, dx, head); V3EQV(B->BALL[i].x, arrows->LINE[offset+3*i+0].x0); V3EQV(head, arrows->LINE[offset+3*i+0].x1); V3EQV(head, arrows->LINE[offset+3*i+1].x0); V3EQV(head, arrows->LINE[offset+3*i+2].x0); V3CROSS(dx, up, perp2); if (V3EQZERO(perp2)) { V3ASSIGN(1.0, 0.0, 0.0,perp); } else { V3CROSS(dx, perp2, perp); V3normalize(perp); } V3mul(head_width*V3LENGTH(dx),perp,perp); V3EQV(dx, head1); V3mul(head_height,head1,head1); V3SUB(head,head1,head1); V3ADD(head1,perp,arrows->LINE[offset+3*i+1].x1); V3SUB(head1,perp,arrows->LINE[offset+3*i+2].x1); } } }
/* Reload the configuration but keeping the rendering state */ void reload_config (int iw, bool term_input_filename) { register int i; int j, k, old_np; char fname[MAX_FILENAME_SIZE], oldfname[MAX_FILENAME_SIZE]; V3 hook_s, tmp, dx; char *old_symbol=NULL; bool incompatible_config; strcpy(oldfname, config_fname); if (n[iw].anchor >= 0) { /* the new configuration may not even have the atom */ V3EQV (B->BALL[n[iw].anchor].x, n[iw].hook); n[iw].anchor = -1; } /* hook_s[] is what is kept invariant */ V3mM3 (n[iw].hook, HI, hook_s); if (term_input_filename) { xterm_get_focus(iw); clear_stdin_buffer(); strcpy(fname,readline_gets("\nLoad configuration",config_fname)); strcpy(config_fname,fname); xterm_release_focus(iw); } if (!Fexists(config_fname)) { printf ("\n** %s: **\n", config_fname); printf ("** There is no such file! **\n"); strcpy(config_fname, oldfname); return; } if (!Freadable(config_fname)) { printf ("\n** %s: **\n", config_fname); printf ("** This file is unreadable! **\n"); strcpy(config_fname, oldfname); return; } cr(); old_np = np; CLONE(symbol, SYMBOL_SIZE*np, char, old_symbol); i = CONFIG_LOAD (config_fname, Config_Aapp_to_Alib); for (k=0; k<CONFIG_num_auxiliary; k++) if (*blank_advance(CONFIG_auxiliary_name[k])==EOS) sprintf(CONFIG_auxiliary_name[k], "auxiliary%d", k); rebind_CT (Config_Aapp_to_Alib, "", ct, &tp); cr(); Neighborlist_Recreate_Form (Config_Aapp_to_Alib, ct, N); if (i == CONFIG_CFG_LOADED) N->s_overflow_err_handler = NEIGHBORLIST_S_OVERFLOW_ERR_HANDLER_FOLD_INTO_PBC; else N->s_overflow_err_handler = NEIGHBORLIST_S_OVERFLOW_ERR_HANDLER_BOUNDING_BOX; N->small_cell_err_handler = NEIGHBORLIST_SMALL_CELL_ERR_HANDLER_MULTIPLY; for (i=0; i<ct->t; i++) for (j=i; j<ct->t; j++) for (k=0; k<rcut_patch_top; k++) if ( ( ( (rcut_patch[k].Zi == ct->Z[i]) && (rcut_patch[k].Zj == ct->Z[j]) ) || ( (rcut_patch[k].Zi == ct->Z[j]) && (rcut_patch[k].Zj == ct->Z[i]) ) ) ) NEIGHBOR_TABLE(N->rcut,ct,i,j) = NEIGHBOR_TABLE(N->rcut,ct,j,i) = rcut_patch[k].rcut; Neighborlist_Recreate (Config_Aapp_to_Alib, stdout, ct, &tp, N); V3mM3 (hook_s, H, tmp); V3SUB (tmp, n[iw].hook, dx); V3EQV (tmp, n[iw].hook); V3AdD (dx, AX_3D[iw].x); M3InV (H, HI, volume); lengthscale = cbrt(volume); V3ASSIGN (0.5,0.5,0.5,tmp); V3mM3 (tmp, H, cm); geo_clear_has_evaluated_flags(); evaluate_geo_measures(); Free(s1); Free(mass); if ( ComputeLeastSquareStrain ) { if (ConfigChecksum(Config_Aapp_to_Alib) != ref->checksum) printf ("This configuration is not isoatomic with the imprinted " "reference\n%s. Least-square strain NOT calculated.\n", ref_fbasename); else LeastSquareStrain_Append(); } incompatible_config = (np != old_np) || memcmp(symbol, old_symbol, SYMBOL_SIZE*MIN(np,old_np)); Free(old_symbol); if (incompatible_config) Config_to_3D_Balls (n[iw].atom_r_ratio); else for (i=0; i<np; i++) V3mM3 ( &(s[DIMENSION*i]), H, B->BALL[i].x ); atom_xtal_origin (n[iw].xtal_origin); if (!n[iw].auxiliary_thresholds_rigid) { for (i=0; i<CONFIG_num_auxiliary; i++) reset_auxiliary_threshold(iw,i); for (i=0; i<MAX_GEO_MEASURES; i++) if (geolist[i].has_evaluated) reset_auxiliary_threshold(iw,CONFIG_MAX_AUXILIARY+i); } if (!temporary_disable_bond) Config_to_3D_Bonds (n[iw].bond_radius); select_fbasename (config_fname); if ((n[iw].xtal_mode) && (n[iw].color_mode == COLOR_MODE_COORD)) assign_coordination_color(iw); else if (n[iw].color_mode == COLOR_MODE_AUXILIARY) color_encode_auxiliary(iw); else if (n[iw].color_mode == COLOR_MODE_SCRATCH) scratch_color (iw); else { strcpy (AX_title[iw],fbasename); AXSetName (iw); XStoreName(AX_display[iw],xterm_win,AX_title[iw]); XSetIconName(AX_display[iw],xterm_win,AX_title[iw]); if (!temporary_disable_bond) { bond_xtal_origin_update (iw); bond_atom_color_update (iw); } } return; } /* end reload_config() */