From 0ed2b585c2c4735a89325b06f491e94675681f67 Mon Sep 17 00:00:00 2001 From: Ksenia Date: Thu, 19 Mar 2026 01:01:30 +0100 Subject: [PATCH 01/13] Print lattice vectors in the extxyz header --- obj/v/ac3_print.d | 3 ++- src/v/ac3_print.c | 47 ++++++++++++++++++++++++++++++----------------- src/v/evr.c | 18 +++++++++--------- src/v/v.h | 6 +++--- 4 files changed, 44 insertions(+), 30 deletions(-) diff --git a/obj/v/ac3_print.d b/obj/v/ac3_print.d index 0ca5016..78de98c 100644 --- a/obj/v/ac3_print.d +++ b/obj/v/ac3_print.d @@ -1,2 +1,3 @@ obj/v/ac3_print.o obj-pic/v/ac3_print.o: src/v/ac3_print.c src/v/v.h \ - src/mol/mol.h src/mol/common.h src/v/pars.h src/math/vec3.h + src/mol/mol.h src/mol/common.h src/v/pars.h src/math/matrix.h \ + src/math/vecn.h src/math/vec3.h diff --git a/src/v/ac3_print.c b/src/v/ac3_print.c index 64a9d1d..9b734d9 100644 --- a/src/v/ac3_print.c +++ b/src/v/ac3_print.c @@ -1,15 +1,16 @@ #include "v.h" +#include "matrix.h" #include "vec3.h" -void ac3_print(atcoord * ac, rendpars rend){ +void ac3_print(atcoord * ac, rendpars * rend){ PRINTOUT(stdout, "$molecule\ncart\n"); for(int k=0; kn; k++){ PRINTOUT(stdout, "%3d % lf % lf % lf", ac->q[k], - rend.xy0[0] + ac->r[k*3 ], - rend.xy0[1] + ac->r[k*3+1], + rend->xy0[0] + ac->r[k*3 ], + rend->xy0[1] + ac->r[k*3+1], ac->r[k*3+2]); - if(rend.bonds>0){ + if(rend->bonds>0){ for(int j=0; jbonds.a[k*BONDS_MAX+j]; if(k1 == -1 ){ @@ -24,8 +25,20 @@ void ac3_print(atcoord * ac, rendpars rend){ return; } -void ac3_print_xyz(atcoord * ac, rendpars rend){ - PRINTOUT(stdout, "%d\n\n", ac->n); +void ac3_print_xyz(atcoord * ac, rendpars * rend, cellpars * cell){ + PRINTOUT(stdout, "%d\n", ac->n); + if(cell->vert==1){ + double C[9]; + mx_multmx(3,3,3, C, rend->ac3rmx, cell->rot_to_lab_basis); + PRINTOUT(stdout, "Lattice=\"%lf %lf %lf %lf %lf %lf %lf %lf %lf\"\n", + C[0], C[3], C[6], + C[1], C[4], C[7], + C[2], C[5], C[8]); + } + else{ + PRINTOUT(stdout, "\n"); + } + for(int k=0; kn; k++){ const char * s = getname(ac->q[k]); int ok = s && s[0]; @@ -36,32 +49,32 @@ void ac3_print_xyz(atcoord * ac, rendpars rend){ PRINTOUT(stdout, " %3d", ac->q[k]); } PRINTOUT(stdout, " % lf % lf % lf\n", - rend.xy0[0] + ac->r[k*3 ], - rend.xy0[1] + ac->r[k*3+1], - ac->r[k*3+2]); + rend->xy0[0] + ac->r[k*3 ], + rend->xy0[1] + ac->r[k*3+1], + ac->r[k*3+2]); } return; } -void ac3_print2fig(atcoord * ac, rendpars rend, double vert[9]){ +void ac3_print2fig(atcoord * ac, rendpars * rend, cellpars * cell){ int n = ac->n; for(int i=0; iq[i], - rend.xy0[0] + ac->r[i*3 ], - rend.xy0[1] + ac->r[i*3+1], + rend->xy0[0] + ac->r[i*3 ], + rend->xy0[1] + ac->r[i*3+1], ac->r[i*3+2]); } - if(vert){ + if(cell->vert==1){ for(int i=0; i<8; i++){ double v[3]; - r3mx(v, vert+3*i, rend.ac3rmx); + r3mx(v, cell->vertices+3*i, rend->ac3rmx); PRINTOUT(stdout, "atom %3d% 13.7lf% 13.7lf% 13.7lf\n", 0, - rend.xy0[0] + v[0], rend.xy0[1] + v[1], v[2]); + rend->xy0[0] + v[0], rend->xy0[1] + v[1], v[2]); } } - if(rend.bonds>0){ + if(rend->bonds>0){ for(int k=0; kbonds.a[k*BONDS_MAX+j]; @@ -75,7 +88,7 @@ void ac3_print2fig(atcoord * ac, rendpars rend, double vert[9]){ } } - if(vert){ + if(cell->vert){ #define LINE(I,J) PRINTOUT(stdout, "bond %3d %3d % 3d\n", (J)+n+1, (I)+n+1, -1) for(int i=0; i<8; i+=2){ LINE(i,i+1); // || z-axis diff --git a/src/v/evr.c b/src/v/evr.c index f502917..1f61216 100644 --- a/src/v/evr.c +++ b/src/v/evr.c @@ -38,14 +38,21 @@ void kp_readagain(object * ent, drawpars * dp){ void kp_print(object * ent, drawpars * dp){ if (dp->task == AT3COORDS){ - ac3_print(ent->m[dp->n], dp->rend); + ac3_print(ent->m[dp->n], &dp->rend); } return; } void kp_print_xyz(object * ent, drawpars * dp){ if (dp->task == AT3COORDS){ - ac3_print_xyz(ent->m[dp->n], dp->rend); + ac3_print_xyz(ent->m[dp->n], &dp->rend, &dp->cell); + } + return; +} + +void kp_print2fig(object * ent, drawpars * dp){ + if (dp->task == AT3COORDS){ + ac3_print2fig(ent->m[dp->n], &dp->rend, &dp->cell); } return; } @@ -60,13 +67,6 @@ void kp_printrot(object * ent __attribute__ ((unused)), drawpars * dp){ return; } -void kp_print2fig(object * ent, drawpars * dp){ - if (dp->task == AT3COORDS){ - ac3_print2fig(ent->m[dp->n], dp->rend, dp->cell.vert==1?dp->cell.vertices:NULL); - } - return; -} - static void rl_changed(object * ent, drawpars * dp){ for(int i=0; in; i++){ ent->m[i]->bonds.flag = 0; diff --git a/src/v/v.h b/src/v/v.h index 05aecae..c778bfa 100644 --- a/src/v/v.h +++ b/src/v/v.h @@ -89,9 +89,9 @@ void redraw_vibro(object * ent, drawpars * dp); // ac3_draw.c void ac3_draw (atcoord * ac, rendpars rend); // ac3_print.c -void ac3_print (atcoord * ac, rendpars rend); -void ac3_print_xyz(atcoord * ac, rendpars rend); -void ac3_print2fig(atcoord * ac, rendpars rend, double * v); +void ac3_print (atcoord * ac, rendpars * rend); +void ac3_print_xyz(atcoord * ac, rendpars * rend, cellpars * cell); +void ac3_print2fig(atcoord * ac, rendpars * rend, cellpars * cell); // bonds.c void bonds_fill(bondpars bond, atcoord * ac); From cbf88658404c88629e14fac3ab06401d05a74a94 Mon Sep 17 00:00:00 2001 From: Ksenia Date: Thu, 19 Mar 2026 01:22:48 +0100 Subject: [PATCH 02/13] Make cellpars.vert a enum + fix printout for drawing with a shell --- src/v/ac3_print.c | 6 +++--- src/v/cli.c | 5 ++--- src/v/evr.c | 2 +- src/v/pars.h | 8 +++++++- src/v/redraw.c | 4 ++-- 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/v/ac3_print.c b/src/v/ac3_print.c index 9b734d9..325230a 100644 --- a/src/v/ac3_print.c +++ b/src/v/ac3_print.c @@ -27,7 +27,7 @@ void ac3_print(atcoord * ac, rendpars * rend){ void ac3_print_xyz(atcoord * ac, rendpars * rend, cellpars * cell){ PRINTOUT(stdout, "%d\n", ac->n); - if(cell->vert==1){ + if(cell->vert==CELL){ double C[9]; mx_multmx(3,3,3, C, rend->ac3rmx, cell->rot_to_lab_basis); PRINTOUT(stdout, "Lattice=\"%lf %lf %lf %lf %lf %lf %lf %lf %lf\"\n", @@ -65,7 +65,7 @@ void ac3_print2fig(atcoord * ac, rendpars * rend, cellpars * cell){ ac->r[i*3+2]); } - if(cell->vert==1){ + if(cell->vert==CELL){ for(int i=0; i<8; i++){ double v[3]; r3mx(v, cell->vertices+3*i, rend->ac3rmx); @@ -88,7 +88,7 @@ void ac3_print2fig(atcoord * ac, rendpars * rend, cellpars * cell){ } } - if(cell->vert){ + if(cell->vert==CELL){ #define LINE(I,J) PRINTOUT(stdout, "bond %3d %3d % 3d\n", (J)+n+1, (I)+n+1, -1) for(int i=0; i<8; i+=2){ LINE(i,i+1); // || z-axis diff --git a/src/v/cli.c b/src/v/cli.c index 21c032c..2318278 100644 --- a/src/v/cli.c +++ b/src/v/cli.c @@ -87,7 +87,7 @@ static int sscan_cell(const char * arg, cellpars * cp){ mx_id(3, cp->rot_to_cell_basis); mx_inv(3, 3, cp->rot_to_cell_basis, rot_to_lab_basis, EPS_INV); - cp->vert = 1; + cp->vert = CELL; return 1; } @@ -106,7 +106,7 @@ static int sscan_shell(const char * arg, cellpars * cp){ if(count == 2){ cp->vertices[0] = shell[0]; cp->vertices[1] = shell[1]; - cp->vert = 2; + cp->vert = SHELL; } return 1; } @@ -194,7 +194,6 @@ static allpars allpars_init(void){ ap.dp.anim.dt = DEFAULT_TIMEOUT; ap.dp.anal.symtol = DEFAULT_SYMTOL; ap.dp.bond.rl = 1.0; - ap.dp.cell.vert = -1; ap.dp.geom.center = 1; ap.dp.rend.r = 1.0; diff --git a/src/v/evr.c b/src/v/evr.c index 1f61216..c805051 100644 --- a/src/v/evr.c +++ b/src/v/evr.c @@ -236,7 +236,7 @@ static void move_ent(object * ent, drawpars * dp, int dir, double step){ if(dp->ui.modkey){ step *= STEP_MOD; } - if(dp->cell.vert == 1){ + if(dp->cell.vert == CELL){ move_pbc(ent, dp, dir, step); } else { diff --git a/src/v/pars.h b/src/v/pars.h index a536b12..960cc6e 100644 --- a/src/v/pars.h +++ b/src/v/pars.h @@ -9,6 +9,12 @@ typedef enum { CPK_COLORS, } colorscheme_t; +typedef enum { + NO_BOUNDARY, + CELL, + SHELL, +} boundary_t; + typedef struct { colorscheme_t colors; // colorscheme (v or cpk) int gui; // if gui is enabled @@ -55,7 +61,7 @@ typedef struct { double vertices[3*8]; // parameters of cell/shell double rot_to_lab_basis[3*3]; // "rotation" matrix for PBC double rot_to_cell_basis[3*3]; // "rotation" matrix for PBC - int vert; // 0: nothing; 1: show cell; 2: show shell + boundary_t vert; } cellpars; typedef struct { diff --git a/src/v/redraw.c b/src/v/redraw.c index 190b134..f3ba047 100644 --- a/src/v/redraw.c +++ b/src/v/redraw.c @@ -83,12 +83,12 @@ void redraw_ac3(object * ent, drawpars * dp){ clear_canv(); ac3_draw(m, dp->rend); ac3_text(m, dp); - if(dp->cell.vert == 1){ + if(dp->cell.vert == CELL){ double v[8*3]; rot3d(8, v, dp->cell.vertices, dp->rend.ac3rmx); drawvertices(v, dp->rend); } - else if(dp->cell.vert == 2){ + else if(dp->cell.vert == SHELL){ drawshell(dp->cell.vertices, dp->rend); } fill_canv(); From 03b4607db80390b3b53def4e572b2849f642c1a8 Mon Sep 17 00:00:00 2001 From: Ksenia Date: Thu, 19 Mar 2026 02:07:05 +0100 Subject: [PATCH 03/13] Give cellpars to each molecule --- obj/v/ac3_read.d | 2 +- obj/v/cli.d | 2 +- src/v/ac3_print.c | 14 ++++++------ src/v/ac3_read.c | 34 ++++++++++++++++++++++++++++ src/v/cli.c | 44 ++++++++++--------------------------- src/v/evr.c | 56 ++++++++++++++++++++++++++--------------------- src/v/pars.h | 5 ++++- src/v/redraw.c | 8 +++---- src/v/v.h | 5 +++-- 9 files changed, 97 insertions(+), 73 deletions(-) diff --git a/obj/v/ac3_read.d b/obj/v/ac3_read.d index 08c3d55..3b18538 100644 --- a/obj/v/ac3_read.d +++ b/obj/v/ac3_read.d @@ -1,3 +1,3 @@ obj/v/ac3_read.o obj-pic/v/ac3_read.o: src/v/ac3_read.c src/v/v.h \ src/mol/mol.h src/mol/common.h src/v/pars.h src/math/vecn.h \ - src/math/vec3.h + src/math/vec3.h src/math/matrix.h src/math/vecn.h diff --git a/obj/v/cli.d b/obj/v/cli.d index b83ea3a..25c9f99 100644 --- a/obj/v/cli.d +++ b/obj/v/cli.d @@ -1,3 +1,3 @@ obj/v/cli.o obj-pic/v/cli.o: src/v/cli.c src/v/v.h src/mol/mol.h \ src/mol/common.h src/v/pars.h src/math/vecn.h src/math/matrix.h \ - src/math/vecn.h src/math/vec3.h + src/math/vecn.h diff --git a/src/v/ac3_print.c b/src/v/ac3_print.c index 325230a..0f71ce4 100644 --- a/src/v/ac3_print.c +++ b/src/v/ac3_print.c @@ -25,11 +25,11 @@ void ac3_print(atcoord * ac, rendpars * rend){ return; } -void ac3_print_xyz(atcoord * ac, rendpars * rend, cellpars * cell){ +void ac3_print_xyz(atcoord * ac, rendpars * rend){ PRINTOUT(stdout, "%d\n", ac->n); - if(cell->vert==CELL){ + if(ac->cell.vert==CELL){ double C[9]; - mx_multmx(3,3,3, C, rend->ac3rmx, cell->rot_to_lab_basis); + mx_multmx(3,3,3, C, rend->ac3rmx, ac->cell.rot_to_lab_basis); PRINTOUT(stdout, "Lattice=\"%lf %lf %lf %lf %lf %lf %lf %lf %lf\"\n", C[0], C[3], C[6], C[1], C[4], C[7], @@ -56,7 +56,7 @@ void ac3_print_xyz(atcoord * ac, rendpars * rend, cellpars * cell){ return; } -void ac3_print2fig(atcoord * ac, rendpars * rend, cellpars * cell){ +void ac3_print2fig(atcoord * ac, rendpars * rend){ int n = ac->n; for(int i=0; iq[i], @@ -65,10 +65,10 @@ void ac3_print2fig(atcoord * ac, rendpars * rend, cellpars * cell){ ac->r[i*3+2]); } - if(cell->vert==CELL){ + if(ac->cell.vert==CELL){ for(int i=0; i<8; i++){ double v[3]; - r3mx(v, cell->vertices+3*i, rend->ac3rmx); + r3mx(v, ac->cell.vertices+3*i, rend->ac3rmx); PRINTOUT(stdout, "atom %3d% 13.7lf% 13.7lf% 13.7lf\n", 0, rend->xy0[0] + v[0], rend->xy0[1] + v[1], v[2]); } @@ -88,7 +88,7 @@ void ac3_print2fig(atcoord * ac, rendpars * rend, cellpars * cell){ } } - if(cell->vert==CELL){ + if(ac->cell.vert==CELL){ #define LINE(I,J) PRINTOUT(stdout, "bond %3d %3d % 3d\n", (J)+n+1, (I)+n+1, -1) for(int i=0; i<8; i+=2){ LINE(i,i+1); // || z-axis diff --git a/src/v/ac3_read.c b/src/v/ac3_read.c index 18e081b..4fb1ade 100644 --- a/src/v/ac3_read.c +++ b/src/v/ac3_read.c @@ -1,6 +1,30 @@ #include "v.h" #include "vecn.h" #include "vec3.h" +#include "matrix.h" + +#define EPS_INV 1e-15 + +static void cell_fill(cellpars * cell, const double abc[9]){ + const double * a = abc+0; + const double * b = abc+3; + const double * c = abc+6; + for(int i=0; i<2; i++){ + for(int j=0; j<2; j++){ + for(int k=0; k<2; k++){ + r3sums3(cell->vertices + (i*4+j*2+k)*3, a, i-0.5, b, j-0.5, c, k-0.5); + } + } + } + double rot_to_lab_basis[9] = {a[0], b[0], c[0], + a[1], b[1], c[1], + a[2], b[2], c[2]}; + veccp(9, cell->rot_to_lab_basis, rot_to_lab_basis); + mx_id(3, cell->rot_to_cell_basis); + mx_inv(3, 3, cell->rot_to_cell_basis, rot_to_lab_basis, EPS_INV); + cell->vert = CELL; + return; +} atcoord * atcoord_fill(mol * m0, int b, const geompars geom){ int n = m0->n; @@ -47,6 +71,16 @@ atcoord * atcoord_fill(mol * m0, int b, const geompars geom){ center_mol(n, m->r, geom.center==2 ? m->q : NULL); } veccp(n*3, m->r0, m->r); + + if(geom.boundary == CELL){ + cell_fill(&m->cell, geom.cell); + } + else if(geom.boundary == SHELL){ + m->cell.vertices[0] = geom.shell[0]; + m->cell.vertices[1] = geom.shell[1]; + m->cell.vert = SHELL; + } + return m; } diff --git a/src/v/cli.c b/src/v/cli.c index 2318278..319f70a 100644 --- a/src/v/cli.c +++ b/src/v/cli.c @@ -1,7 +1,6 @@ #include "v.h" #include "vecn.h" #include "matrix.h" -#include "vec3.h" #define EPS_INV 1e-15 @@ -37,7 +36,7 @@ static int sscan_rot(const char * arg, double ac3rmx[9]){ return 1; } -static int sscan_cell(const char * arg, cellpars * cp){ +static int sscan_cell(const char * arg, geompars * geom){ double cell[9]; int count = sscanf(arg, "cell:b%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf", cell, cell+1, cell+2, cell+3, cell+4, cell+5, cell+6, cell+7, cell+8); if(count > 0){ @@ -60,38 +59,19 @@ static int sscan_cell(const char * arg, cellpars * cp){ } } - double a[3]={}, b[3]={}, c[3]={}; if(count==3){ - a[0] = cell[0]; - b[1] = cell[1]; - c[2] = cell[2]; + geom->cell[0] = cell[0]; + geom->cell[4] = cell[1]; + geom->cell[8] = cell[2]; } else{ - r3cp(a, cell+0); - r3cp(b, cell+3); - r3cp(c, cell+6); + veccp(9, geom->cell, cell); } - - for(int i=0; i<2; i++){ - for(int j=0; j<2; j++){ - for(int k=0; k<2; k++){ - r3sums3(cp->vertices + (i*4+j*2+k)*3, a, i-0.5, b, j-0.5, c, k-0.5); - } - } - } - - double rot_to_lab_basis[9] = {a[0], b[0], c[0], - a[1], b[1], c[1], - a[2], b[2], c[2]}; - veccp(9, cp->rot_to_lab_basis, rot_to_lab_basis); - mx_id(3, cp->rot_to_cell_basis); - mx_inv(3, 3, cp->rot_to_cell_basis, rot_to_lab_basis, EPS_INV); - - cp->vert = CELL; + geom->boundary = CELL; return 1; } -static int sscan_shell(const char * arg, cellpars * cp){ +static int sscan_shell(const char * arg, geompars * geom){ double shell[2]; int count = sscanf(arg, "shell:b%lf,%lf", shell, shell+1); if(count > 0){ @@ -104,9 +84,9 @@ static int sscan_shell(const char * arg, cellpars * cp){ if(count <= 0) return 0; if(count == 2){ - cp->vertices[0] = shell[0]; - cp->vertices[1] = shell[1]; - cp->vert = SHELL; + geom->shell[0] = shell[0]; + geom->shell[1] = shell[1]; + geom->boundary = SHELL; } return 1; } @@ -135,8 +115,8 @@ static int cli_parse_arg(char * arg, allpars * ap){ || lazysscanf(arg, "exitcom:", &dp->ui.on_exit) || lazysscanf(arg, "colors:", &ts) || sscan_rot (arg, dp->rend.ac3rmx) - || sscan_cell (arg, &dp->cell) - || sscan_shell(arg, &dp->cell) + || sscan_cell (arg, &dp->geom) + || sscan_shell(arg, &dp->geom) ; if(vib==0){ diff --git a/src/v/evr.c b/src/v/evr.c index c805051..cf115ae 100644 --- a/src/v/evr.c +++ b/src/v/evr.c @@ -45,14 +45,14 @@ void kp_print(object * ent, drawpars * dp){ void kp_print_xyz(object * ent, drawpars * dp){ if (dp->task == AT3COORDS){ - ac3_print_xyz(ent->m[dp->n], &dp->rend, &dp->cell); + ac3_print_xyz(ent->m[dp->n], &dp->rend); } return; } void kp_print2fig(object * ent, drawpars * dp){ if (dp->task == AT3COORDS){ - ac3_print2fig(ent->m[dp->n], &dp->rend, &dp->cell); + ac3_print2fig(ent->m[dp->n], &dp->rend); } return; } @@ -209,25 +209,17 @@ static void mol2cell(double r[3], cellpars * cell){ return; } -static void move_pbc(object * acs, drawpars * dp, int dir, double d){ - - double dr[3], v[3] = {}; - v[dir] = d; // translation in the view basis - r3mxt(dr, v, dp->rend.ac3rmx); // translation in the mol basis. - // not true if the initial "rotation" from CLI is not unitary, but ignore this - for(int i=0; in; i++){ - atcoord * m = acs->m[i]; - for(int j=0; jn; j++){ - double * r = m->r0+j*3; - r3add(r, dr); - mol2cell(r, &dp->cell); - r3cp(m->r+j*3, r); - m->rotated = 0; - } - if(dp->rend.bonds>0){ - m->bonds.flag = 0; - m->bonds.rl *= RL_MOVE_PBC_SCALE; - } +static void move_pbc(atcoord * m, drawpars * dp, double dr[3]){ + for(int j=0; jn; j++){ + double * r = m->r0+j*3; + r3add(r, dr); + mol2cell(r, &m->cell);///TODO + r3cp(m->r+j*3, r); + m->rotated = 0; + } + if(dp->rend.bonds>0){ + m->bonds.flag = 0; + m->bonds.rl *= RL_MOVE_PBC_SCALE; } return; } @@ -236,11 +228,25 @@ static void move_ent(object * ent, drawpars * dp, int dir, double step){ if(dp->ui.modkey){ step *= STEP_MOD; } - if(dp->cell.vert == CELL){ - move_pbc(ent, dp, dir, step); - } - else { + + if(dp->task==VIBRO){ dp->rend.xy0[dir] += step; + return; + } + + double dr[3], v[3] = {}; + v[dir] = step; // translation in the view basis + r3mxt(dr, v, dp->rend.ac3rmx); // translation in the mol basis. + // not true if the initial "rotation" from CLI is not unitary, but ignore this + + for(int i=0; in; i++){ + atcoord * m = ent->m[i]; + if(m->cell.vert == CELL){ + move_pbc(m, dp, dr); + } + else { + dp->rend.xy0[dir] += step; // TODO probably set xy0 when show something with boundary==CELL in redraw + } } return; } diff --git a/src/v/pars.h b/src/v/pars.h index 960cc6e..3010e6a 100644 --- a/src/v/pars.h +++ b/src/v/pars.h @@ -32,6 +32,10 @@ typedef struct { int center; // 0: nothing; 1: center each molecule upon reading; 2: center wrt center of mass int inertia; // 0: nothing; 1: rotate each molecule upon reading wrt axis of inertia int bohr; // 0: Å 1: Bohr + + boundary_t boundary; + double cell[9]; + double shell[2]; } geompars; typedef struct { @@ -87,7 +91,6 @@ typedef struct { uipars ui; rendpars rend; bondpars bond; - cellpars cell; animpars anim; analpars anal; diff --git a/src/v/redraw.c b/src/v/redraw.c index f3ba047..2f8e06a 100644 --- a/src/v/redraw.c +++ b/src/v/redraw.c @@ -83,13 +83,13 @@ void redraw_ac3(object * ent, drawpars * dp){ clear_canv(); ac3_draw(m, dp->rend); ac3_text(m, dp); - if(dp->cell.vert == CELL){ + if(m->cell.vert == CELL){ double v[8*3]; - rot3d(8, v, dp->cell.vertices, dp->rend.ac3rmx); + rot3d(8, v, m->cell.vertices, dp->rend.ac3rmx); drawvertices(v, dp->rend); } - else if(dp->cell.vert == SHELL){ - drawshell(dp->cell.vertices, dp->rend); + else if(m->cell.vert == SHELL){ + drawshell(m->cell.vertices, dp->rend); } fill_canv(); return; diff --git a/src/v/v.h b/src/v/v.h index c778bfa..85afd9c 100644 --- a/src/v/v.h +++ b/src/v/v.h @@ -39,6 +39,7 @@ typedef struct { int nf[2]; // number of molecule in file, file size styp sym; // point group bondstr bonds; + cellpars cell; } atcoord; typedef struct { @@ -90,8 +91,8 @@ void redraw_vibro(object * ent, drawpars * dp); void ac3_draw (atcoord * ac, rendpars rend); // ac3_print.c void ac3_print (atcoord * ac, rendpars * rend); -void ac3_print_xyz(atcoord * ac, rendpars * rend, cellpars * cell); -void ac3_print2fig(atcoord * ac, rendpars * rend, cellpars * cell); +void ac3_print_xyz(atcoord * ac, rendpars * rend); +void ac3_print2fig(atcoord * ac, rendpars * rend); // bonds.c void bonds_fill(bondpars bond, atcoord * ac); From 49af3d39279d32ca1bd912b272f164c27f2a98fd Mon Sep 17 00:00:00 2001 From: Ksenia Date: Thu, 19 Mar 2026 03:27:00 +0100 Subject: [PATCH 04/13] Parse extxyz's lattice TODO: use it --- src/v/ac3_read_xyz.c | 73 +++++++++++++++++++++++++++++++++++++------- src/v/v.h | 1 - 2 files changed, 62 insertions(+), 12 deletions(-) diff --git a/src/v/ac3_read_xyz.c b/src/v/ac3_read_xyz.c index 02a3205..08eef79 100644 --- a/src/v/ac3_read_xyz.c +++ b/src/v/ac3_read_xyz.c @@ -1,5 +1,50 @@ #include "v.h" +static inline int eat_line(FILE * f){ + char c; + do{ + c = fgetc(f); + if(c==EOF){ + return -1; + } + } while(c!='\n'); + return 0; +} + +int read_header(FILE * f, double cell[9]){ + + const char pattern[] = "Lattice=\""; + + int c, i=0, found=0; + do{ + c = fgetc(f); + if(c==EOF){ + return -1; + } + if(c==pattern[i]){ + if(++i==sizeof(pattern)-1){ + found = 1; + break; + } + } + else{ + i=0; + } + } while(c!='\n'); + + if(!found){ + return 0; + } + + int ret = (fscanf(f, "%lf%lf%lf%lf%lf%lf%lf%lf%lf", cell, cell+1, cell+2, cell+3, cell+4, cell+5, cell+6, cell+7, cell+8)==9); + + if(eat_line(f)){ + return -1; + } + + return ret; +} + mol * ac3_read_xyz(FILE * f){ // count atoms @@ -7,27 +52,33 @@ mol * ac3_read_xyz(FILE * f){ if(fscanf(f, "%d", &n) != 1){ return NULL; } + fgetc(f); - // skip the comment line - int c = fgetc(f); - do{ - c = fgetc(f); - if(c==EOF){ - GOTOHELL; - } - } while(c!='\n'); + // read header + double cell[9]; + int r = read_header(f, cell); + if(r==-1){ + return NULL; + } + else if(r==1){ + // read successfully -- TODO + printf("%d\n", r); + } // fill in mol * m = alloc_mol(n); - char tmp_str[BIGSTRLEN]; for(int i=0; ir+3*i, m->r+3*i+1, m->r+3*i+2, tmp_str) < 4) { + if (fscanf (f, "%7s%lf%lf%lf", type, m->r+3*i, m->r+3*i+1, m->r+3*i+2) != 4){ free(m); return NULL; } m->q[i] = get_element(type); + + if(eat_line(f)){ + free(m); + return NULL; + } } return m; diff --git a/src/v/v.h b/src/v/v.h index 85afd9c..f01bf7b 100644 --- a/src/v/v.h +++ b/src/v/v.h @@ -6,7 +6,6 @@ #define BONDS_MAX 32 #define POINTER_SPEED 2.0 #define STRLEN 256 -#define BIGSTRLEN 4096 #define MAX_LINES 5 #include "pars.h" From 6a999a038831660d31f154cce69ad8ee6f7d4646 Mon Sep 17 00:00:00 2001 From: Ksenia Date: Thu, 19 Mar 2026 03:39:10 +0100 Subject: [PATCH 05/13] Use Lattice for mols --- obj/v/ac3_read_xyz.d | 2 +- src/v/ac3_read.c | 13 +++++++++---- src/v/ac3_read_xyz.c | 11 ++++++----- src/v/load.c | 4 ++-- src/v/v.h | 4 ++-- 5 files changed, 20 insertions(+), 14 deletions(-) diff --git a/obj/v/ac3_read_xyz.d b/obj/v/ac3_read_xyz.d index 9faf7c0..ccd0291 100644 --- a/obj/v/ac3_read_xyz.d +++ b/obj/v/ac3_read_xyz.d @@ -1,2 +1,2 @@ obj/v/ac3_read_xyz.o obj-pic/v/ac3_read_xyz.o: src/v/ac3_read_xyz.c \ - src/v/v.h src/mol/mol.h src/mol/common.h src/v/pars.h + src/v/v.h src/mol/mol.h src/mol/common.h src/v/pars.h src/math/vecn.h diff --git a/src/v/ac3_read.c b/src/v/ac3_read.c index 4fb1ade..b4c6cd7 100644 --- a/src/v/ac3_read.c +++ b/src/v/ac3_read.c @@ -26,7 +26,7 @@ static void cell_fill(cellpars * cell, const double abc[9]){ return; } -atcoord * atcoord_fill(mol * m0, int b, const geompars geom){ +atcoord * atcoord_fill(mol * m0, const int b, const geompars geom, const double cell[9]){ int n = m0->n; size_t q_size = sizeof(int ) * n; @@ -80,6 +80,9 @@ atcoord * atcoord_fill(mol * m0, int b, const geompars geom){ m->cell.vertices[1] = geom.shell[1]; m->cell.vert = SHELL; } + else if(cell!=NULL){ + cell_fill(&m->cell, cell); + } return m; } @@ -88,10 +91,12 @@ atcoord * ac3_read(readpars read, int b, const geompars geom, format_t * format) mol * m = NULL; FILE * f = read.f; + int cell_found = 0; + double cell[9] = {}; switch(*format){ case XYZ: - if((m=ac3_read_xyz(f))){ + if((m=ac3_read_xyz(f, &cell_found, cell))){ *format = XYZ; } break; @@ -106,7 +111,7 @@ atcoord * ac3_read(readpars read, int b, const geompars geom, format_t * format) } break; default: - if((m=ac3_read_xyz(f))){ + if((m=ac3_read_xyz(f, &cell_found, cell))){ *format = XYZ; } if(!m){ @@ -126,7 +131,7 @@ atcoord * ac3_read(readpars read, int b, const geompars geom, format_t * format) } m->name = read.fname; - atcoord * M = atcoord_fill(m, b, geom); + atcoord * M = atcoord_fill(m, b, geom, cell_found ? cell : NULL); free(m); return M; } diff --git a/src/v/ac3_read_xyz.c b/src/v/ac3_read_xyz.c index 08eef79..9660352 100644 --- a/src/v/ac3_read_xyz.c +++ b/src/v/ac3_read_xyz.c @@ -1,4 +1,5 @@ #include "v.h" +#include "vecn.h" static inline int eat_line(FILE * f){ char c; @@ -45,7 +46,7 @@ int read_header(FILE * f, double cell[9]){ return ret; } -mol * ac3_read_xyz(FILE * f){ +mol * ac3_read_xyz(FILE * f, int * cell_found, double * cell){ // count atoms int n = 0; @@ -55,14 +56,14 @@ mol * ac3_read_xyz(FILE * f){ fgetc(f); // read header - double cell[9]; - int r = read_header(f, cell); + double tcell[9]; + int r = read_header(f, tcell); if(r==-1){ return NULL; } else if(r==1){ - // read successfully -- TODO - printf("%d\n", r); + veccp(9, cell, tcell); + *cell_found = 1; } // fill in diff --git a/src/v/load.c b/src/v/load.c index d211db9..2210c9a 100644 --- a/src/v/load.c +++ b/src/v/load.c @@ -191,7 +191,7 @@ object * acs_from_var(int n, mol * m, vibr_t vib, allpars * ap){ ent->vib = NULL; for(int i=0; im[i] = atcoord_fill(m+i, dp->rend.bonds, dp->geom); + ent->m[i] = atcoord_fill(m+i, dp->rend.bonds, dp->geom, NULL); } fill_nf(ent, 0); @@ -207,7 +207,7 @@ object * acs_from_var(int n, mol * m, vibr_t vib, allpars * ap){ else{ ent->Nmem = ent->n = 1; ent->m = malloc(ent->Nmem*sizeof(atcoord *)); - ent->m[0] = atcoord_fill(m+n-1, dp->rend.bonds, dp->geom); + ent->m[0] = atcoord_fill(m+n-1, dp->rend.bonds, dp->geom, NULL); int nat = ent->m[0]->n; ent->vib = make_vibr_t(vib.n, nat); veccp(vib.n*nat*3, ent->vib->disp, vib.disp); diff --git a/src/v/v.h b/src/v/v.h index f01bf7b..caba7c1 100644 --- a/src/v/v.h +++ b/src/v/v.h @@ -68,11 +68,11 @@ vibr_t * make_vibr_t(int n_modes, int n_atoms); vibr_t * mode_read(FILE * f, int na); // ac3_read*.c int read_cart_atom(FILE * f, int n, mol * m); -atcoord * atcoord_fill(mol * m, int b, geompars geom); +atcoord * atcoord_fill(mol * m0, const int b, const geompars geom, const double cell[9]); atcoord * ac3_read(readpars read, int b, geompars geom, format_t * format); mol * ac3_read_in (FILE * f); mol * ac3_read_out(FILE * f); -mol * ac3_read_xyz(FILE * f); +mol * ac3_read_xyz(FILE * f, int * lattice_found, double * lattice); // man.c void printman(FILE * f, char * exename); From 3d2641f122da75b743db67c6dc8a99d2247bb2e3 Mon Sep 17 00:00:00 2001 From: Ksenia Date: Thu, 19 Mar 2026 03:55:29 +0100 Subject: [PATCH 06/13] Move correctly TODO: disable cell from CLI --- src/v/evr.c | 18 ++++++++++-------- src/v/redraw.c | 4 ++++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/v/evr.c b/src/v/evr.c index cf115ae..81d6f6e 100644 --- a/src/v/evr.c +++ b/src/v/evr.c @@ -225,11 +225,13 @@ static void move_pbc(atcoord * m, drawpars * dp, double dr[3]){ } static void move_ent(object * ent, drawpars * dp, int dir, double step){ + atcoord * m = ent->m[dp->n]; + if(dp->ui.modkey){ step *= STEP_MOD; } - if(dp->task==VIBRO){ + if((dp->task==VIBRO) || (m->cell.vert != CELL)){ dp->rend.xy0[dir] += step; return; } @@ -239,15 +241,15 @@ static void move_ent(object * ent, drawpars * dp, int dir, double step){ r3mxt(dr, v, dp->rend.ac3rmx); // translation in the mol basis. // not true if the initial "rotation" from CLI is not unitary, but ignore this - for(int i=0; in; i++){ - atcoord * m = ent->m[i]; - if(m->cell.vert == CELL){ - move_pbc(m, dp, dr); - } - else { - dp->rend.xy0[dir] += step; // TODO probably set xy0 when show something with boundary==CELL in redraw + if(dp->geom.boundary==CELL){ + // all have the same cell -> move together, otherwise move separately + for(int i=0; in; i++){ + move_pbc(ent->m[i], dp, dr); } } + else{ + move_pbc(m, dp, dr); + } return; } diff --git a/src/v/redraw.c b/src/v/redraw.c index 2f8e06a..c4dd805 100644 --- a/src/v/redraw.c +++ b/src/v/redraw.c @@ -79,6 +79,10 @@ void redraw_ac3(object * ent, drawpars * dp){ atcoord * m = ent->m[dp->n]; fill_bonds(m, dp); rotate_mol(m, dp); + if(m->cell.vert == CELL){ + dp->rend.xy0[0] = 0.0; + dp->rend.xy0[1] = 0.0; + } clear_canv(); ac3_draw(m, dp->rend); From dce1b81faea2c2f05f23f4e7d63c4fec1ca5ebc8 Mon Sep 17 00:00:00 2001 From: Ksenia Date: Thu, 19 Mar 2026 04:03:37 +0100 Subject: [PATCH 07/13] Rename vert to boundary --- src/v/ac3_print.c | 6 +++--- src/v/ac3_read.c | 4 ++-- src/v/evr.c | 2 +- src/v/pars.h | 2 +- src/v/redraw.c | 6 +++--- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/v/ac3_print.c b/src/v/ac3_print.c index 0f71ce4..b7e22eb 100644 --- a/src/v/ac3_print.c +++ b/src/v/ac3_print.c @@ -27,7 +27,7 @@ void ac3_print(atcoord * ac, rendpars * rend){ void ac3_print_xyz(atcoord * ac, rendpars * rend){ PRINTOUT(stdout, "%d\n", ac->n); - if(ac->cell.vert==CELL){ + if(ac->cell.boundary==CELL){ double C[9]; mx_multmx(3,3,3, C, rend->ac3rmx, ac->cell.rot_to_lab_basis); PRINTOUT(stdout, "Lattice=\"%lf %lf %lf %lf %lf %lf %lf %lf %lf\"\n", @@ -65,7 +65,7 @@ void ac3_print2fig(atcoord * ac, rendpars * rend){ ac->r[i*3+2]); } - if(ac->cell.vert==CELL){ + if(ac->cell.boundary==CELL){ for(int i=0; i<8; i++){ double v[3]; r3mx(v, ac->cell.vertices+3*i, rend->ac3rmx); @@ -88,7 +88,7 @@ void ac3_print2fig(atcoord * ac, rendpars * rend){ } } - if(ac->cell.vert==CELL){ + if(ac->cell.boundary==CELL){ #define LINE(I,J) PRINTOUT(stdout, "bond %3d %3d % 3d\n", (J)+n+1, (I)+n+1, -1) for(int i=0; i<8; i+=2){ LINE(i,i+1); // || z-axis diff --git a/src/v/ac3_read.c b/src/v/ac3_read.c index b4c6cd7..96c0a7f 100644 --- a/src/v/ac3_read.c +++ b/src/v/ac3_read.c @@ -22,7 +22,7 @@ static void cell_fill(cellpars * cell, const double abc[9]){ veccp(9, cell->rot_to_lab_basis, rot_to_lab_basis); mx_id(3, cell->rot_to_cell_basis); mx_inv(3, 3, cell->rot_to_cell_basis, rot_to_lab_basis, EPS_INV); - cell->vert = CELL; + cell->boundary = CELL; return; } @@ -78,7 +78,7 @@ atcoord * atcoord_fill(mol * m0, const int b, const geompars geom, const double else if(geom.boundary == SHELL){ m->cell.vertices[0] = geom.shell[0]; m->cell.vertices[1] = geom.shell[1]; - m->cell.vert = SHELL; + m->cell.boundary = SHELL; } else if(cell!=NULL){ cell_fill(&m->cell, cell); diff --git a/src/v/evr.c b/src/v/evr.c index 81d6f6e..d81ae67 100644 --- a/src/v/evr.c +++ b/src/v/evr.c @@ -231,7 +231,7 @@ static void move_ent(object * ent, drawpars * dp, int dir, double step){ step *= STEP_MOD; } - if((dp->task==VIBRO) || (m->cell.vert != CELL)){ + if((dp->task==VIBRO) || (m->cell.boundary != CELL)){ dp->rend.xy0[dir] += step; return; } diff --git a/src/v/pars.h b/src/v/pars.h index 3010e6a..198afe3 100644 --- a/src/v/pars.h +++ b/src/v/pars.h @@ -65,7 +65,7 @@ typedef struct { double vertices[3*8]; // parameters of cell/shell double rot_to_lab_basis[3*3]; // "rotation" matrix for PBC double rot_to_cell_basis[3*3]; // "rotation" matrix for PBC - boundary_t vert; + boundary_t boundary; } cellpars; typedef struct { diff --git a/src/v/redraw.c b/src/v/redraw.c index c4dd805..d931984 100644 --- a/src/v/redraw.c +++ b/src/v/redraw.c @@ -79,7 +79,7 @@ void redraw_ac3(object * ent, drawpars * dp){ atcoord * m = ent->m[dp->n]; fill_bonds(m, dp); rotate_mol(m, dp); - if(m->cell.vert == CELL){ + if(m->cell.boundary== CELL){ dp->rend.xy0[0] = 0.0; dp->rend.xy0[1] = 0.0; } @@ -87,12 +87,12 @@ void redraw_ac3(object * ent, drawpars * dp){ clear_canv(); ac3_draw(m, dp->rend); ac3_text(m, dp); - if(m->cell.vert == CELL){ + if(m->cell.boundary== CELL){ double v[8*3]; rot3d(8, v, m->cell.vertices, dp->rend.ac3rmx); drawvertices(v, dp->rend); } - else if(m->cell.vert == SHELL){ + else if(m->cell.boundary== SHELL){ drawshell(m->cell.vertices, dp->rend); } fill_canv(); From aa21b4b22ff6655b03e7209984741e475e5769b8 Mon Sep 17 00:00:00 2001 From: Ksenia Date: Thu, 19 Mar 2026 04:18:56 +0100 Subject: [PATCH 08/13] Override extxyz lattice with cell:0 --- src/v/ac3_read.c | 2 +- src/v/cli.c | 26 ++++++++++++++++++++------ src/v/pars.h | 1 + 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/v/ac3_read.c b/src/v/ac3_read.c index 96c0a7f..2e5c1df 100644 --- a/src/v/ac3_read.c +++ b/src/v/ac3_read.c @@ -80,7 +80,7 @@ atcoord * atcoord_fill(mol * m0, const int b, const geompars geom, const double m->cell.vertices[1] = geom.shell[1]; m->cell.boundary = SHELL; } - else if(cell!=NULL){ + else if(cell && geom.boundary!=CELL_DISABLED){ cell_fill(&m->cell, cell); } diff --git a/src/v/cli.c b/src/v/cli.c index 319f70a..386ef05 100644 --- a/src/v/cli.c +++ b/src/v/cli.c @@ -2,7 +2,7 @@ #include "vecn.h" #include "matrix.h" -#define EPS_INV 1e-15 +#define EPS 1e-15 static int lazysscanf(char * const s, const char * const template, char ** ret){ // if the string `s` begins with the template, @@ -40,11 +40,11 @@ static int sscan_cell(const char * arg, geompars * geom){ double cell[9]; int count = sscanf(arg, "cell:b%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf", cell, cell+1, cell+2, cell+3, cell+4, cell+5, cell+6, cell+7, cell+8); if(count > 0){ - if(count==9 || count==3){ + if(count==9 || count==3 || count==1){ vecscal(count, cell, BA); } else{ - PRINT_WARN("option `cell:b` takes exactly 3 or 9 comma-separated arguments\n") + PRINT_WARN("option `cell:b` takes exactly 1, 3 or 9 comma-separated arguments\n") return 1; } } @@ -53,13 +53,27 @@ static int sscan_cell(const char * arg, geompars * geom){ if(count <= 0){ return 0; } - else if(count!=3 && count!=9){ - PRINT_WARN("option `cell:` takes exactly 3 or 9 comma-separated arguments\n") + else if(count!=3 && count!=9 && count!=1){ + PRINT_WARN("option `cell:` takes exactly 1, 3, or 9 comma-separated arguments\n") return 1; } } - if(count==3){ + double s=0.0; + for(int i=0; iboundary = CELL_DISABLED; + return 1; + } + + if(count==1){ + geom->cell[0] = cell[0]; + geom->cell[4] = cell[0]; + geom->cell[8] = cell[0]; + } + else if(count==3){ geom->cell[0] = cell[0]; geom->cell[4] = cell[1]; geom->cell[8] = cell[2]; diff --git a/src/v/pars.h b/src/v/pars.h index 198afe3..01029d0 100644 --- a/src/v/pars.h +++ b/src/v/pars.h @@ -13,6 +13,7 @@ typedef enum { NO_BOUNDARY, CELL, SHELL, + CELL_DISABLED, } boundary_t; typedef struct { From ce0768f496d1f65808c2ecbbcc009c45774d09eb Mon Sep 17 00:00:00 2001 From: Ksenia Date: Fri, 20 Mar 2026 14:05:21 +0100 Subject: [PATCH 09/13] Make shell: take 1 or 2 args --- src/v/cli.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/v/cli.c b/src/v/cli.c index 386ef05..80a55a9 100644 --- a/src/v/cli.c +++ b/src/v/cli.c @@ -89,20 +89,20 @@ static int sscan_shell(const char * arg, geompars * geom){ double shell[2]; int count = sscanf(arg, "shell:b%lf,%lf", shell, shell+1); if(count > 0){ - if(count==2) - vecscal(count, shell, BA); + vecscal(count, shell, BA); } else{ count = sscanf(arg, "shell:%lf,%lf", shell, shell+1); } - if(count <= 0) - return 0; - if(count == 2){ + if(count>0){ geom->shell[0] = shell[0]; - geom->shell[1] = shell[1]; + geom->shell[1] = shell[count>1]; geom->boundary = SHELL; + return 1; + } + else{ + return 0; } - return 1; } static int cli_parse_arg(char * arg, allpars * ap){ From 45b4b26a873082dc7a3c84ae9d15f3ff905855d9 Mon Sep 17 00:00:00 2001 From: Ksenia Date: Fri, 20 Mar 2026 14:41:52 +0100 Subject: [PATCH 10/13] Add cell/shell to scaling --- src/v/scale.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/v/scale.c b/src/v/scale.c index 4721933..a5ba651 100644 --- a/src/v/scale.c +++ b/src/v/scale.c @@ -15,6 +15,17 @@ double ac3_scale(atcoord * ac){ double d2 = r3d2(center, ac->r+3*k); d2max = MAX(d2max, d2+rad*rad); } + if(ac->cell.boundary==SHELL){ + for(int i=0; i<2; i++){ + d2max = MAX(d2max, 2*ac->cell.vertices[i]*ac->cell.vertices[i]); + } + } + else if(ac->cell.boundary==CELL){ + for(int k=0; k<8; k++){ + double d2 = r3d2(center, ac->cell.vertices+3*k); + d2max = MAX(d2max, d2); + } + } return VIEWPORT_FILL / sqrt(d2max); } From b76c3da50697710d37f8067cd2fa8067ebfe0e18 Mon Sep 17 00:00:00 2001 From: Ksenia Date: Fri, 20 Mar 2026 14:47:06 +0100 Subject: [PATCH 11/13] Draw cell/shell when vib:1 as well --- src/v/redraw.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/v/redraw.c b/src/v/redraw.c index d931984..2bd31c2 100644 --- a/src/v/redraw.c +++ b/src/v/redraw.c @@ -1,6 +1,18 @@ #include "v.h" #include "evr.h" +static void draw_boundary(atcoord * m , rendpars * rend){ + if(m->cell.boundary==CELL){ + double v[8*3]; + rot3d(8, v, m->cell.vertices, rend->ac3rmx); + drawvertices(v, *rend); + } + else if(m->cell.boundary==SHELL){ + drawshell(m->cell.vertices, *rend); + } + return; +} + static void ac3_text(atcoord * ac, drawpars * dp){ char text[32]; char text_fname[STRLEN]; @@ -79,7 +91,7 @@ void redraw_ac3(object * ent, drawpars * dp){ atcoord * m = ent->m[dp->n]; fill_bonds(m, dp); rotate_mol(m, dp); - if(m->cell.boundary== CELL){ + if(m->cell.boundary==CELL){ dp->rend.xy0[0] = 0.0; dp->rend.xy0[1] = 0.0; } @@ -87,30 +99,22 @@ void redraw_ac3(object * ent, drawpars * dp){ clear_canv(); ac3_draw(m, dp->rend); ac3_text(m, dp); - if(m->cell.boundary== CELL){ - double v[8*3]; - rot3d(8, v, m->cell.vertices, dp->rend.ac3rmx); - drawvertices(v, dp->rend); - } - else if(m->cell.boundary== SHELL){ - drawshell(m->cell.vertices, dp->rend); - } + draw_boundary(m, &dp->rend); fill_canv(); return; } void redraw_vibro(object * ent, drawpars * dp){ - atcoord * m = ent->m[0]; - double * dr = ent->vib->disp + dp->n * m->n*3; - fill_bonds(m, dp); + double * dr = ent->vib->disp + dp->n * m->n*3; vecsums(m->n*3, m->r, m->r0, dr, VIBR_AMP*sqrt(m->n)*sin(dp->anim.t * 2.0*M_PI/TMAX)); rot3d_inplace(m->n, m->r, dp->rend.ac3rmx); clear_canv(); ac3_draw(m, dp->rend); vibro_text(ent->vib, dp); + draw_boundary(m, &dp->rend); fill_canv(); return; } From 8f1a79cf1fc659f81bc11e3c66863250fcfcb480 Mon Sep 17 00:00:00 2001 From: Ksenia Date: Fri, 20 Mar 2026 14:53:27 +0100 Subject: [PATCH 12/13] Pass rend by pointer --- src/v/ac3_draw.c | 16 ++++++++-------- src/v/redraw.c | 8 ++++---- src/v/v.h | 6 +++--- src/v/x.c | 8 ++++---- src/v/x.h | 4 ++-- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/v/ac3_draw.c b/src/v/ac3_draw.c index d06b405..664b166 100644 --- a/src/v/ac3_draw.c +++ b/src/v/ac3_draw.c @@ -28,20 +28,20 @@ static int cmpz(const void * p1, const void * p2){ return 0; } -void ac3_draw(atcoord * ac, rendpars rend){ +void ac3_draw(atcoord * ac, rendpars * rend){ int n = ac->n; kzstr * kz = malloc(sizeof(kzstr)*n); - int * ks = (rend.bonds>0) ? malloc(sizeof(int)*n) : NULL; + int * ks = (rend->bonds>0) ? malloc(sizeof(int)*n) : NULL; double resol = world.size * RESOL_SCALE; - double r1 = rend.r * resol * rend.scale; + double r1 = rend->r * resol * rend->scale; for(int k=0; kr[k*3+2]; } qsort(kz, n, sizeof(kzstr), cmpz); - if(rend.bonds>0){ + if(rend->bonds>0){ for(int i=0; i0?world.gc_black:world.gc_dot[1], x-r, y-r, 2*r, 2*r, 0, 360*64); } - if(rend.num == 1){ + if(rend->num == 1){ char text[16]; snprintf(text, sizeof(text), "%d", k+1); XDRAWSTRING(world.dis, world.canv, world.gc_black, x, y, text, strlen(text)); } - else if(rend.num == -1){ + else if(rend->num == -1){ char text[16]; const char * s = getname(q); s ? snprintf(text, sizeof(text), "%s", s) : snprintf(text, sizeof(text), "%d", q ); XDRAWSTRING(world.dis, world.canv, world.gc_black, x, y, text, strlen(text)); } - if(rend.bonds>0){ + if(rend->bonds>0){ for(int j=k*BONDS_MAX; j<(k+1)*BONDS_MAX; j++){ int k1 = ac->bonds.a[j]; if(k1 == -1 ){ @@ -92,7 +92,7 @@ void ac3_draw(atcoord * ac, rendpars rend){ } double dd = BOND_OFFSET * r / sqrt(r2d); XDrawLine(world.dis, world.canv, world.gc_black, x+dd*dx, y+dd*dy, x1, y1); - if(rend.bonds==2){ + if(rend->bonds==2){ char text[16]; snprintf(text, sizeof(text), "%.3lf", ac->bonds.r[j]); XDRAWSTRING(world.dis, world.canv, world.gc_black, x+dx/2, y+dy/2, text, strlen(text)); diff --git a/src/v/redraw.c b/src/v/redraw.c index 2bd31c2..a077034 100644 --- a/src/v/redraw.c +++ b/src/v/redraw.c @@ -5,10 +5,10 @@ static void draw_boundary(atcoord * m , rendpars * rend){ if(m->cell.boundary==CELL){ double v[8*3]; rot3d(8, v, m->cell.vertices, rend->ac3rmx); - drawvertices(v, *rend); + draw_vertices(v, rend); } else if(m->cell.boundary==SHELL){ - drawshell(m->cell.vertices, *rend); + draw_shell(m->cell.vertices, rend); } return; } @@ -97,7 +97,7 @@ void redraw_ac3(object * ent, drawpars * dp){ } clear_canv(); - ac3_draw(m, dp->rend); + ac3_draw(m, &dp->rend); ac3_text(m, dp); draw_boundary(m, &dp->rend); fill_canv(); @@ -112,7 +112,7 @@ void redraw_vibro(object * ent, drawpars * dp){ rot3d_inplace(m->n, m->r, dp->rend.ac3rmx); clear_canv(); - ac3_draw(m, dp->rend); + ac3_draw(m, &dp->rend); vibro_text(ent->vib, dp); draw_boundary(m, &dp->rend); fill_canv(); diff --git a/src/v/v.h b/src/v/v.h index caba7c1..f8dc1ff 100644 --- a/src/v/v.h +++ b/src/v/v.h @@ -87,7 +87,7 @@ void redraw_ac3(object * ent, drawpars * dp); void redraw_vibro(object * ent, drawpars * dp); // ac3_draw.c -void ac3_draw (atcoord * ac, rendpars rend); +void ac3_draw (atcoord * ac, rendpars * rend); // ac3_print.c void ac3_print (atcoord * ac, rendpars * rend); void ac3_print_xyz(atcoord * ac, rendpars * rend); @@ -107,8 +107,8 @@ void init_x (const char * const capt, const colorscheme_t colorscheme); void init_font (char * fontname); void textincorner (const char * const lines[MAX_LINES], const int red[MAX_LINES]); void setcaption (const char * const capt); -void drawvertices (double * v, rendpars rend); -void drawshell (double r[2], rendpars rend); +void draw_vertices(double * v, rendpars * rend); +void draw_shell (double r[2], rendpars * rend); int savepic (char * s); void clear_canv(); void fill_canv(); diff --git a/src/v/x.c b/src/v/x.c index d28333a..b6df6e2 100644 --- a/src/v/x.c +++ b/src/v/x.c @@ -153,14 +153,14 @@ void setcaption(const char * const capt){ return; } -void draw_edge(double vi[3], double vj[3], rendpars rend){ +void draw_edge(double vi[3], double vj[3], rendpars * rend){ int iw = (vi[2]>0.0 || vj[2]>0.0) ? 0 : 1; XDrawLine(world.dis, world.canv, world.gc_dot[iw], SCREEN_X(vi[0]), SCREEN_Y(vi[1]), SCREEN_X(vj[0]), SCREEN_Y(vj[1])); return; } -void drawvertices(double * v, rendpars rend){ +void draw_vertices(double * v, rendpars * rend){ #define LINE(i,j) draw_edge(v+(i)*3, v+(j)*3, rend) for(int i=0; i<8; i+=2){ LINE(i,i+1); // || z-axis @@ -175,8 +175,8 @@ void drawvertices(double * v, rendpars rend){ return; } -void drawshell(double r[2], rendpars rend){ - double d = world.size * rend.scale; +void draw_shell(double r[2], rendpars * rend){ + double d = world.size * rend->scale; for(int i=0; i<2; i++){ XDrawArc(world.dis, world.canv, world.gc_dot[1-i], SCREEN_X(-r[i]), SCREEN_Y(r[i]), diff --git a/src/v/x.h b/src/v/x.h index 17698c2..e85aa30 100644 --- a/src/v/x.h +++ b/src/v/x.h @@ -7,8 +7,8 @@ #define NCOLORS 110 #define LINE_WIDTH 2 -#define SCREEN_X(X) (world.W/2 + world.size * rend.scale*(rend.xy0[0] + (X))) -#define SCREEN_Y(Y) (world.H/2 - world.size * rend.scale*(rend.xy0[1] + (Y))) +#define SCREEN_X(X) (world.W/2 + world.size * rend->scale*(rend->xy0[0] + (X))) +#define SCREEN_Y(Y) (world.H/2 - world.size * rend->scale*(rend->xy0[1] + (Y))) typedef struct { Display * dis; From 713d1182ae207d53875892824e562b1ceebeb2eb Mon Sep 17 00:00:00 2001 From: Ksenia Date: Fri, 20 Mar 2026 17:48:27 +0100 Subject: [PATCH 13/13] Update readme --- .github/CHANGELOG.md | 3 +- README.md | 73 +++++++++++++++++++++++++++++++++++++++----- 2 files changed, 68 insertions(+), 8 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 727a9cb..4fe1c87 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -3,6 +3,7 @@ ### New features * Add partial extended xyz support (https://github.com/briling/v/pull/18) +* Read and print lattice parameters to/from extxyz header (#39) * Add `j` hotkey to jump to a frame inside and CLI option `frame:%d` to start with a specific frame (https://github.com/briling/v/pull/5) * Add `bmax` CLI argument for max. bond length (920202b) * Add `com` and `exitcom` CLI argument for `gui:0` and on-exit command sequences, respectively @@ -17,6 +18,7 @@ * Read molecules from the standard input (#28) * Show infrared intensities and mode masses (#35) * Improve the text-in-corner look (de242c7, #36) +* Add `u` to the headless mode (#37) * Improve data structures and code readability ### Fixes @@ -28,7 +30,6 @@ * Fix text blinking when playing animation (80cae88, #36) ### Coming in the next version: -* extended xyz (#16, #17) * high-symmetry determination bugs (#21) * how to build on mac (#34) diff --git a/README.md b/README.md index 525a1fd..b546187 100644 --- a/README.md +++ b/README.md @@ -45,13 +45,14 @@ To build: ``` ./v file [file2 ... fileN] [options] ``` -A filename `-` stands for the standard input. +A filename `-` stands for the standard input (xyz files only). Show the reference: ``` ./v ``` +### Options
Command-line options | | | @@ -81,6 +82,7 @@ Show the reference:
+### Keyboard
Keyboard reference | | | @@ -120,15 +122,17 @@ Show the reference:
-
Mouse (in development) +### Mouse + One can also use the mouse to rotate the molecule and zoom in/out. -
-
Headless mode (in development) +### Additional commands -If run in the headless mode with `gui:0`, the symbols from the standard input are processed +#### Headless mode + +If run in the headless mode with `gui:0`, the symbols from the standard input are processed as if the corresponding keys were pressed in the normal mode. -Right now, only `p`, `x`, `z`, and `.` are available. +Right now, `p`, `x`, `z`, `u`, and `.` are available. Command-line option `com:%s` overrides the standard input. These examples are equivalent: ``` @@ -142,8 +146,60 @@ D*h D*h ``` +#### Normal mode +In the normal mode, the symbols from the CLI option `exitcom:` are executed immediately before closing. +For example, +``` +./v mol/mol0001.xyz exitcom:z +``` +automatically prints the last xyz coordinates when the user closes the window. + + + + +### Boundary conditions +Two types of boundary conditions are recognized: +* PBC (3D) +* spherical confinement + +#### PBC +PBC can be read from the xyz [file header](https://ase-lib.org/ase/io/formatoptions.html#extxyz) +by specifying `Lattice="ax ay az bx by bz cx cy cz"`: +``` +./v mol/MOL_3525.ext.xyz +``` +Currently, only the PBC in all three dimensions are supported. + +The same can be passed via the command-line, in which case it overrides the one from the file: +``` +./v mol/MOL_3525.xyz cell:8.929542,0,0,4.197206,8.892922,0,0.480945,2.324788,10.016044 +``` +For orthogonal/cubic cell: +``` +./v mol/1372_D02.340_1.out bonds:0 cell:20.23,20.23,20.23 +./v mol/1372_D02.340_1.out bonds:0 cell:20.23 +``` +In Bohr instead of Å: +``` +./v mol/1372_D02.340_1.out bonds:0 cell:b10.7 +``` +Finally, to disable the cell from the file: +``` +./v mol/MOL_3525.ext.xyz cell:0 +``` + +#### Spherical confinement +Spherical confinement can be specified from the command-line by the following: +``` +./v mol/mol0001.xyz shell:2 # sphere with r = 2 Å is put around the molecule +./v mol/mol0001.xyz shell:b4 # sphere with r = 2 Bohr +./v mol/mol0001.xyz shell:2,3 # spheres with r = 2 and 3 Å (e.g., soft and hard boundaries) +./v mol/mol0001.xyz shell:b4,5 # spheres with r = 4 and 5 Bohr +``` +
+ ## Examples [↑](#contents) * `mol/C3H6~mCPBA_01x11.qm.out` — geometries + vibrations ``` @@ -166,7 +222,7 @@ D*h ![Adamantane mode animation](figures/C10H16.qm.out.gif) * `mol/1372_D02.340_1.out` — PBC simulation ``` -./v mol/1372_D02.340_1.out bonds:0 cell:b10.7,10.7,1.07 font:-*-*-medium-*-*--15-*-*-*-*-*-*-1 +./v mol/1372_D02.340_1.out bonds:0 cell:b10.7 font:-*-*-medium-*-*--15-*-*-*-*-*-*-1 ``` ![Atoms in cell with PBC](figures/1372_D02.340_1.out_1087.gif) * `mol/mol0001.xyz`, `mol/mol0002.xyz` — `.xyz` files with atomic numbers and atomic symbols @@ -177,6 +233,9 @@ D*h * `mol/MOL_3525.xyz` — organic crystal with non-orthogonal cell ``` +./v mol/MOL_3525.ext.xyz +``` +``` ./v mol/MOL_3525.xyz cell:8.929542,0.0,0.0,4.197206,8.892922,0.0,0.480945,2.324788,10.016044 font:-*-*-medium-*-*--15-*-*-*-*-*-*-1 ``` ![Organic crystal cell](figures/MOL_3525.xyz_1.gif)