| Bsoft 2.0.5 Bernard's software package

symmetry.cpp
Go to the documentation of this file.
1
9 #include "symmetry.h"
10 #include "random_numbers.h"
11 #include "Euler.h"
12 #include "linked_list.h"
13 #include "utilities.h"
14
15 // Declaration of global variables
16 extern int verbose; // Level of output to the screen
17
39 Bsymmetry* init_point_group_symmetry(Bstring symmetry_string)
40 {
41 int i, theorder, helix_dyad = 1;
42 double helix_rise = 1, helix_angle = M_PI;
43 Matrix3 mat(0,-1,0,1,0,0,0,0,1); // 90 degree rotation for I90
44
45 Bsymmetry* sym = new Bsymmetry;
46 memset(sym, 0, sizeof(Bsymmetry));
47
48 sym->label = symmetry_clean_pointgroup(symmetry_string);
49
50 if ( verbose & VERB_FULL )
51 cout << endl << "Getting symmetry operators for " << sym->label << endl;
52
53 if ( sym->label[0] == 'C' ) { // Cyclic point groups
54 if ( sym->label == "Cs" ) theorder = 1; // Reflection
55 else theorder = sym->label.substr(1,10).integer();
56 sym->n = 1;
57 sym->point = 100 + theorder;
58 sym->op = new Bsymop[sym->n]; memset(sym->op, 0, sym->n*sizeof(Bsymop));;
59 sym->op[0].axis[2] = 1;
60 sym->op[0].order = theorder;
61 sym->op[0].angle = M_PI*2.0L/theorder;
62 } else if ( sym->label[0] == 'D' ) { // Dihedral point groups
63 theorder = sym->label.substr(1,10).integer();
64 sym->n = 2;
65 sym->point = 200 + theorder;
66 sym->op = new Bsymop[sym->n]; memset(sym->op, 0, sym->n*sizeof(Bsymop));;
67 sym->op[0].axis[2] = 1;
68 sym->op[0].order = theorder;
69 sym->op[0].angle = M_PI*2.0L/theorder;
70 sym->op[1].axis[0] = 1; // Rotate around 2-fold x-axis
71 sym->op[1].order = 2;
72 sym->op[1].angle = M_PI;
73 } else if ( sym->label[0] == 'T' ) { // Tetrahedral point group
74 sym->point = 320;
75 sym->n = 3;
76 if ( sym->label.contains("-3") ) sym->n = 2;
77 sym->op = new Bsymop[sym->n]; memset(sym->op, 0, sym->n*sizeof(Bsymop));;
78 i = 0;
79 if ( !sym->label.contains("-3") ) {
80 sym->op[i].axis[0] = sym->op[i].axis[1] =
81 sym->op[i].axis[2] = 1; // Rotate around 3-fold (1,1,1)
82 sym->op[i].order = 3;
83 sym->op[i].angle = M_PI*2.0L/3.0;
84 i++;
85 }
86 sym->op[i].axis[2] = 1; // Rotate around 2-fold z-axis
87 sym->op[i].order = 2;
88 sym->op[i].angle = M_PI;
89 i++;
90 sym->op[i].axis[0] = 1; // Rotate around 2-fold x-axis
91 sym->op[i].order = 2;
92 sym->op[i].angle = M_PI;
93 } else if ( sym->label[0] == 'O' ) { // Octahedral point group
94 sym->point = 432;
95 sym->n = 3;
96 if ( sym->label.contains("-") ) sym->n = 2;
97 sym->op = new Bsymop[sym->n]; memset(sym->op, 0, sym->n*sizeof(Bsymop));;
98 i = 0;
99 if ( !sym->label.contains("-3") ) {
100 sym->op[i].axis[0] = sym->op[i].axis[1] =
101 sym->op[i].axis[2] = 1; // Rotate around 3-fold (1,1,1)
102 sym->op[i].order = 3;
103 sym->op[i].angle = M_PI*2.0L/3.0;
104 i++;
105 }
106 if ( sym->label.contains("-4") ) {
107 sym->op[i].axis[0] = 1; // Rotate around 2-fold
108 sym->op[i].axis[1] = -1;
109 sym->op[i].order = 2;
110 sym->op[i].angle = M_PI;
111 } else if ( sym->label.contains("-2") ) {
112 sym->op[i].axis[2] = 1; // Rotate around 4-fold z-axis
113 sym->op[i].order = 4;
114 sym->op[i].angle = M_PI_2;
115 } else {
116 sym->op[i].axis[2] = 1; // Rotate around 4-fold z-axis
117 sym->op[i].order = 4;
118 sym->op[i].angle = M_PI_2;
119 i++;
120 sym->op[i].axis[0] = 1; // Rotate around 2-fold x-axis
121 sym->op[i].order = 2;
122 sym->op[i].angle = M_PI;
123 }
124 } else if ( sym->label[0] == 'I' ) { // Icosahedral point group
125 sym->point = 532;
126 sym->n = 4;
127 if ( sym->label.contains("-") ) sym->n = 3;
128 sym->op = new Bsymop[sym->n]; memset(sym->op, 0, sym->n*sizeof(Bsymop));;
129 i = 0;
130 if ( !sym->label.contains("-3") ) {
131 sym->op[i].axis[0] = sym->op[i].axis[1] = sym->op[i].axis[2] = 1; // Rotate around 3-fold (1,1,1)
132 sym->op[i].order = 3;
133 sym->op[i].angle = M_PI*2.0L/3.0;
134 i++;
135 }
136 if ( sym->label.contains("-5") ) {
137 sym->op[i].axis[0] = 1; // Rotate around 2-fold
138 } else if ( sym->label.contains("-2") ) {
139 sym->op[i].axis[0] = 1; // Rotate around 2-fold
140 sym->op[i].axis[1] = -1;
141 sym->op[i].order = 2;
142 sym->op[i].angle = M_PI;
143 } else {
144 sym->op[i].axis[0] = 1; // Rotate around 2-fold
145 sym->op[i].axis[1] = 1.0L/GOLDEN;
146 sym->op[i].axis[2] = GOLDEN;
147 }
148 sym->op[i].order = 2;
149 sym->op[i].angle = M_PI;
150 i++;
151 if ( !sym->label.contains("-5") ) {
152 sym->op[i].axis[0] = 1.0L/GOLDEN; // Rotate around 5-fold
153 sym->op[i].axis[1] = 1;
154 sym->op[i].order = 5;
155 sym->op[i].angle = M_PI*2.0L/5.0;
156 i++;
157 }
158 if ( !sym->label.contains("-2") ) {
159 sym->op[i].axis[2] = 1; // Rotate around 2-fold z-axis
160 sym->op[i].order = 2;
161 sym->op[i].angle = M_PI;
162 }
163 if ( sym->label.contains("90") )
164 for ( i=0; i<sym->n; i++ )
165 sym->op[i].axis = mat * sym->op[i].axis;
166 } else if ( sym->label[0] == 'H' ) { // Helical symmetry
167 sscanf(sym->label.c_str(), "H%lf,%lf,%d", &helix_rise, &helix_angle, &helix_dyad);
168 sym->n = 1;
169 if ( helix_dyad == 2 ) sym->n = 2;
170 sym->op = new Bsymop[sym->n]; memset(sym->op, 0, sym->n*sizeof(Bsymop));;
171 sym->point = 600;
172 sym->op[0].axis[2] = 1; // Helical axis
173 sym->op[0].shift = helix_rise; // Rise in angstrom
174 sym->op[0].angle = helix_angle*M_PI/180.0L;
175 if ( helix_dyad == 2 ) {
176 sym->op[1].axis[0] = 1; // Dyad axis
177 sym->op[1].order = 2;
178 sym->op[1].angle = M_PI;
179 }
180 } else {
181 error_show("Error in init_point_group_symmetry", __FILE__, __LINE__);
182 cerr << "This is not a valid symmetry designation: " << sym->label << endl;
183 kill_symmetry(sym);
184 return NULL;
185 }
186
187 for ( i=0; i<sym->n; i++ )
188 sym->op[i].axis.normalize();
189
190 if ( verbose & VERB_DEBUG )
191 cout << "DEBUG init_point_group_symmetry: label=" << sym->label << endl;
192
193 return sym;
194 }
195
196 Bsymmetry* init_point_group_symmetry()
197 {
198 Bstring symmetry_string("C1");
199 return init_point_group_symmetry(symmetry_string);
200 }
201
207 int kill_symmetry(Bsymmetry* sym)
208 {
209 if ( !sym ) return 0;
210
211 if ( sym->n > 0 && sym->op ) delete[] sym->op;
212
213 delete sym;
214
215 return 0;
216 }
217
226 Bstring symmetry_clean_pointgroup(Bstring& symmetry_string)
227 {
228 int j(0);
229
230 Bstring clean_sym_str = "C1";
231
232 if ( verbose & VERB_DEBUG )
233 cout << "DEBUG symmetry_clean_pointgroup: symmetry_string=" << symmetry_string << endl;
234
235 if ( symmetry_string.length() < 1 ) return clean_sym_str;
236
237 // Remove leading blanks and convert to upper case
238 clean_sym_str = symmetry_string.no_space();
239
240 // Alternate nomenclature for point groups
241 if ( isdigit(clean_sym_str[0]) ) {
242 j = clean_sym_str.integer();
243 if ( clean_sym_str.contains("532") && clean_sym_str.contains("90") )
244 clean_sym_str = "I90";
245 else if ( clean_sym_str.contains("532") )
246 clean_sym_str = "I";
247 else if ( clean_sym_str.contains("432") )
248 clean_sym_str = "O";
249 else if ( clean_sym_str.contains("23") )
250 clean_sym_str = "T";
251 else if ( j > 1 && clean_sym_str[1] == 2 )
252 clean_sym_str = Bstring(j, "D%d");
253 else if ( j > 0 )
254 clean_sym_str = Bstring(j, "C%d");
255 else
256 clean_sym_str = "C1";
257 }
258
259 clean_sym_str[0] = toupper(clean_sym_str[0]);
260
261 if ( verbose & VERB_DEBUG )
262 cout << "DEBUG symmetry_clean_pointgroup: clean_sym_str=" << clean_sym_str << endl;
263
264 return clean_sym_str;
265 }
266
280 string symmetry_helical_label(double helix_rise, double helix_angle,
281 int dyad_axis, int cyclic, double seam_shift)
282 {
283 string label = "H" + to_string(helix_rise);
284 label += "," + to_string(helix_angle*180.0/M_PI);
285 label += "," + to_string(dyad_axis);
286 label += "," + to_string(cyclic);
287 label += "," + to_string(seam_shift);
288
289 return label;
290 }
291
301 int symmetry_order(Bsymmetry* sym)
302 {
303 int i, order(1);
304
305 for ( i=0; i<sym->n; i++ ) order *= sym->op[i].order;
306
307 return order;
308 }
309
315 View view_symmetry_reference(Bsymmetry* sym)
316 {
317 View ref;
318
319 if ( sym->point < 200 ) {
320 ref[0] = 1;
321 ref[2] = 0;
322 } else if ( sym->point < 300 ) {
323 ref[0] = sin(M_PI/4);
324 ref[2] = cos(M_PI/4);
325 } else if ( sym->point == 320 ) {
326 ref[0] = sin(M_PI/4);
327 ref[2] = cos(M_PI/4);
328 } else if ( sym->point == 432 ) {
329 ref[0] = sin(M_PI/8);
330 ref[2] = cos(M_PI/8);
331 } else if ( sym->point == 532 ) {
332 ref[0] = sin(M_PI/18);
333 ref[2] = cos(M_PI/18);
334 } else if ( sym->point == 600 ) { // What is it for helical symmetry?
335 }
336
337 return ref;
338 }
339
347 Matrix3 symmetry_rotate_to_axis(Bsymmetry* sym, long axis, long axis_flag)
348 {
349 double sqrt2(sqrt(2));
350 Matrix3 mat(1), mat2(1);
351
352 if ( axis_flag ) mat2 = Matrix3(Vector3<double>(0,0,1), M_PI_2);
353
354 if ( sym->point < 200 ) { // Cyclic
355 } else if ( sym->point < 300 ) { // Dihedral
356 if ( axis_flag ) mat2 = Matrix3(Vector3<double>(0,0,1), M_PI/sym->op[0].order);
357 if ( axis > 2 ) mat = Matrix3(Vector3<double>(0,1,0), M_PI_2);
358 } else if ( sym->point < 400 ) { // Tetrahedral
359 if ( axis == 3 ) mat = Matrix3(Vector3<double>(-1/sqrt2,1/sqrt2,0), atan(sqrt2));
360 } else if ( sym->point < 500 ) { // Octahedral
361 if ( axis == 3 ) mat = Matrix3(Vector3<double>(-1/sqrt2,1/sqrt2,0), atan(sqrt2));
362 if ( axis == 2 ) mat = Matrix3(Vector3<double>(0,1,0), M_PI/4);
363 } else { // Icosahedral
364 if ( axis == 3 ) mat = Matrix3(Vector3<double>(0,1,0), atan(1/(GOLDEN*sqrt(3))));
365 if ( axis == 5 ) mat = Matrix3(Vector3<double>(1,0,0), atan(1/GOLDEN));
366 }
367
368 mat = mat2*mat;
369
370 return mat;
371 }
372
379 Vector3<double>* symmetry_get_axes(Bsymmetry* sym, long& nax)
380 {
381 long i, j, k, m, ns;
382 Vector3<double> axis1;
383 Matrix3 mat;
384
385 if ( verbose & VERB_DEBUG )
386 cout << "DEBUG symmetry_get_axes: label=" << sym->label << endl;
387
388 if ( sym->point < 300 ) { // Cyclic and dihedral
389 axis1[2] = 1;
390 } else if ( sym->point < 400 ) { // Tetrahedral
391 axis1[0] = axis1[1] = axis1[2] = 1/sqrt(3.0);
392 } else if ( sym->point < 500 ) { // Octahedral
393 if ( sym->label.contains("-4") ) {
394 axis1[2] = 1;
395 } else if ( sym->label.contains("-3") ) {
396 axis1[0] = axis1[1] = axis1[2] = 1/sqrt(3.0);
397 } else {
398 cerr << "Error: The symmetry designation must be either O-3 or O-4!" << endl;
399 return NULL;
400 }
401 } else if ( sym->point < 600 ) { // Icosahedral
402 if ( sym->label.contains("-5") ) {
403 axis1[1] = 1/sqrt(2+GOLDEN);
404 axis1[2] = 1/sqrt(3-GOLDEN);
405 } else if ( sym->label.contains("-3") ) {
406 axis1[0] = axis1[1] = axis1[2] = 1/sqrt(3.0);
407 } else {
408 cerr << "Error: The symmetry designation must be either I-3 or I-5!" << endl;
409 return NULL;
410 }
411 }
412
413 for ( i=0, nax=1; i<sym->n; i++ ) nax *= sym->op[i].order;
414
415 if ( verbose & VERB_DEBUG )
416 cout << "DEBUG symmetry_get_axes: nax=" << nax << endl;
417
418 Vector3<double>* axis = new Vector3<double>[nax];
419 for ( i=0; i<nax; i++ ) axis[i] = 0;
420
421 axis[0] = axis1;
422
423 for ( i=0, k=1, ns=1; i<sym->n; i++ ) {
424 for ( j=1; j<sym->op[i].order; j++ ) {
425 mat = Matrix3(sym->op[i].axis, j*TWOPI/sym->op[i].order);
426 for ( m=0; m<ns; m++ ) axis[k++] = mat * axis[m];
427 }
428 ns = k;
429 }
430
431 if ( verbose & VERB_FULL )
432 for ( i=0; i<nax; i++ ) cout << "Axis[" << i+1 << "]: " << axis[i] << endl;
433
434 return axis;
435 }
436
448 View* symmetry_get_all_views(Bsymmetry* sym, View asu_view)
449 {
450 int i, j, k;
451 double angle;
452 Quaternion q, qv;
453
454 View* view = NULL;
455 View* v;
456 View* vn = (View *) add_item((char **) &view, sizeof(View));
457 *vn = asu_view;
458 vn->normalize();
459 vn->next = NULL;
460
461 if ( verbose & VERB_FULL ) {
462 cout << "Getting all the symmetric views:" << endl;
463 cout << "Symmetry: " << sym->label << endl;
464 cout << "View: " << asu_view << endl;
465 }
466
467 int nview(1);
468 for ( i=0; i<sym->n; i++ ) {
469 for ( j=1; j<sym->op[i].order; j++ ) {
470 angle = j*TWOPI*1.0L/sym->op[i].order;
471 q = Quaternion(sym->op[i].axis, angle);
472 for ( k=0, v=view; k<nview; k++, v=v->next ) {
473 qv = v->quaternion();
474 qv = q * qv;
475 // vn = (View *) add_item((char **) &view, sizeof(View));
476 vn = (View *) add_item((char **) &vn, sizeof(View));
477 *vn = View(qv);
478 if ( verbose & VERB_DEBUG )
479 cout << "DEBUG symmetry_get_all_views: " << vn << endl;
480 }
481 }
482 nview *= sym->op[i].order;
483 }
484
485 if ( verbose & VERB_FULL )
486 for ( i=1, v=view; v; v=v->next, i++ )
487 cout << "View " << i << ": " << tab << *v << endl;
488
489 return view;
490 }
491
492 View* symmetry_get_all_views(Bsymmetry* sym, View* views)
493 {
494 View* v;
495 View* vt;
496 View* vc = NULL;
497 View* vn = NULL;
498
499 for ( v=views; v; v=v->next ) {
500 vt = symmetry_get_all_views(sym, *v);
501 if ( vc ) vc->next = vt;
502 else vn = vc = vt;
503 while ( vc->next ) vc = vc->next;
504 }
505
506 return vn;
507 }
508
520 Matrix3* symmetry_get_all_matrices(Bsymmetry* sym, long& nsym)
521 {
522 int i, j, k, n, ns;
523 double angle;
524 Matrix3 mt;
525
526 for ( i=0, ns=1; i<sym->n; i++ ) ns *= sym->op[i].order;
527 Matrix3* mat = new Matrix3[ns];
528 for ( i=0; i<ns; i++ ) mat[i] = Matrix3(1);
529
530 if ( verbose & VERB_FULL ) {
531 cout << "Getting all the symmetric matrices:" << endl;
532 cout << "Symmetry: " << sym->label << endl;
533 }
534
535 for ( i=0, n=ns=1; i<sym->n; i++ ) {
536 for ( j=1; j<sym->op[i].order; j++ ) {
537 angle = j*TWOPI*1.0L/sym->op[i].order;
538 mt = Matrix3(sym->op[i].axis, angle);
539 for ( k=0; k<ns; k++ )
540 mat[n++] = mt*mat[k];
541 }
542 ns *= sym->op[i].order;
543 }
544
545 if ( verbose & VERB_FULL ) {
546 for ( i=0; i<ns; i++ ) {
547 cout << "Matrix " << i+1 << ":" << endl;
548 matrix3_show_hp(mat[i]);
549 }
550 }
551
552 nsym = ns;
553
554 return mat;
555 }
556
570 View* asymmetric_unit_views(Bsymmetry* sym, double theta_step, double phi_step, int flag)
571 {
572 if ( theta_step < M_PI/1800 ) theta_step = M_PI/180;
573 if ( phi_step < M_PI/1800 ) phi_step = M_PI/180;
574
575 int temp_sym = 0;
576 if ( !sym ) {
577 temp_sym = 1;
578 sym = init_point_group_symmetry();
579 }
580
581 char full = flag & 1;
582 char inplanerot = !(flag & 2);
583 int i, j, n = 0, ntheta, nphi, nrphi, istart;
584 double theta, phi, max_theta, theta_start, phi_start, phi_end;
585
586 if ( verbose & VERB_DEBUG )
587 cout << "DEBUG asymmetric_unit_views: flag=" << flag << " full=" << full << endl;
588
589 max_theta = M_PI_2 + 1e-6; // Most symmetries limited to upper half
590 ntheta = (int) (max_theta/theta_step + 0.5);
591 nphi = (int) (M_PI*2.0/(sym->op[0].order*phi_step) + 0.5);
592
593 if ( sym->point < 200 ) {
594 if ( full ) {
595 max_theta = M_PI + 1e-6;
596 ntheta += ntheta;
597 }
598 } else if ( sym->point == 432 ) {
599 max_theta = M_PI_4 + 1e-6;
600 ntheta = (int) (max_theta/theta_step + 0.5);
601 } else if ( sym->point == 532 ) {
602 max_theta = atan(1/(GOLDEN+1)) + 1e-6;
603 ntheta = (int) (max_theta/theta_step + 2.5);
604 nphi = (int) (atan(1/GOLDEN)/phi_step + 1.5);
605 } else if ( sym->point == 600 ) {
606 ntheta = 1;
607 nphi = (int) (M_PI*2.0/phi_step + 1);
608 }
609
610 if ( ntheta < 1 ) ntheta = 1;
611 if ( nphi < 1 ) nphi = 1;
612
613 if ( verbose & (VERB_PROCESS | VERB_LABEL) ) {
614 if ( full )
615 cout << "Getting all the asymmetric unit views for symmetry " << sym->label << endl;
616 else
617 cout << "Getting half the asymmetric unit views for symmetry " << sym->label << endl;
618 cout << "Theta and phi step sizes: " <<
619 theta_step*180/M_PI << " " << phi_step*180/M_PI << " degrees" << endl;
620 cout << "Theta and phi steps: " << ntheta << " " << nphi << endl;
621 }
622
623 if ( verbose & VERB_DEBUG )
624 cout << "DEBUG asymmetric_unit_views: Views allocated = " << 2*ntheta*nphi << endl;
625
626 View* view = NULL;
627 View* v = NULL;
628
629 if ( sym->point < 500 ) { // Top view for all but icosahedral and helical symmetry
630 v = (View *) add_item((char **) &view, sizeof(View));
631 (*v)[2] = 1;
632 n = 1;
633 if ( verbose & VERB_DEBUG )
634 cout << "DEBUG asymmetric_unit_views: Adding the top view" << endl;
635 }
636
637 if ( sym->point > 100 && sym->point < 200 ) {
638 for ( theta=theta_step; theta<=max_theta; theta+=theta_step ) {
639 nrphi = (int) (nphi*sin(theta)/2 + 0.5); // Number of views at this radius and theta
640 phi = istart = 0;
641 if ( nrphi ) {
642 phi = M_PI*1.0/(sym->op[0].order*nrphi);
643 istart = -nrphi;
644 if ( sym->point < 102 ) nrphi -= 1;
645 }
646 for ( j=istart; j<=nrphi; j++ ) {
647 v = (View *) add_item((char **) &view, sizeof(View));
648 *v = View(sin(theta)*cos(j*phi), sin(theta)*sin(j*phi), cos(theta), 0);
649 if ( inplanerot ) (*v)[3] = j*phi;
650 n++;
651 }
652 }
653 if ( full && v->z() > -0.999999 ) {
654 v = (View *) add_item((char **) &view, sizeof(View));
655 (*v)[2] = -1;
656 n++;
657 }
658 } else if ( sym->point > 200 && sym->point < 300 ) {
659 for ( theta=theta_step; theta<=max_theta; theta+=theta_step ) {
660 nrphi = (int) (nphi*sin(theta)/2 + 0.5); // Number of views at this radius and theta
661 phi = 0;
662 if ( nrphi ) phi = M_PI*1.0/(sym->op[0].order*nrphi);
663 istart = 0;
664 if ( full ) istart = -nrphi;
665 for ( j=istart; j<=nrphi; j++ ) {
666 v = (View *) add_item((char **) &view, sizeof(View));
667 *v = View(sin(theta)*cos(j*phi), sin(theta)*sin(j*phi), cos(theta), 0);
668 if ( inplanerot ) (*v)[3] = j*phi;
669 n++;
670 }
671 }
672 } else if ( sym->point == 320 ) {
673 for ( theta=theta_step; theta<=max_theta; theta+=theta_step ) {
674 phi_start = 0;
675 phi_end = theta;
676 if ( theta > M_PI_4 ) phi_end = M_PI_2 - theta;
677 if ( full ) phi_start = -theta;
678 if ( full && theta > M_PI_4 ) phi_start = theta - M_PI_2;
679 for ( phi=phi_start; phi<=phi_end; phi+=phi_step ) {
680 v = (View *) add_item((char **) &view, sizeof(View));
681 *v = View(sin(theta), sin(phi), cos(theta), 0);
682 n++;
683 }
684 }
685 } else if ( sym->point == 432 ) {
686 for ( theta=theta_step; theta<=max_theta; theta+=theta_step ) {
687 phi_start = 0;
688 if ( full ) phi_start = -theta;
689 for ( phi=phi_start; phi<=theta; phi+=phi_step ) {
690 v = (View *) add_item((char **) &view, sizeof(View));
691 *v = View(sin(theta), sin(phi), cos(theta), 0);
692 n++;
693 }
694 }
695 } else if ( sym->point == 532 ) {
696 if ( sym->label.contains("I90") ) {
697 theta_start = 0;
698 if ( full ) theta_start = -ntheta*theta_step;
699 for ( theta=theta_start; theta<=max_theta; theta+=theta_step ) {
700 for ( phi=0; phi<=GOLDEN*(max_theta - fabs(theta)); phi+=phi_step ) {
701 v = (View *) add_item((char **) &view, sizeof(View));
702 *v = View(tan(phi), tan(theta), cos(theta), 0);
703 n++;
704 }
705 }
706 } else {
707 for ( theta=0; theta<=max_theta; theta+=theta_step ) {
708 nrphi = (int) (GOLDEN*(max_theta - theta)/phi_step);
709 phi_start = 0;
710 if ( full ) phi_start = -nrphi*phi_step;
711 for ( phi=phi_start; phi<=GOLDEN*(max_theta - theta); phi+=phi_step ) {
712 v = (View *) add_item((char **) &view, sizeof(View));
713 *v = View(tan(theta), tan(phi), cos(theta), 0);
714 n++;
715 }
716 }
717 }
718 } else if ( sym->point == 600 ) { // Helical symmetry
719 for ( phi = 0; phi < TWOPI-0.001; phi += phi_step ) {
720 v = (View *) add_item((char **) &view, sizeof(View));
721 *v = View(cos(phi), sin(phi), 0, 0);
722 if ( inplanerot ) (*v)[3] = phi;
723 n++;
724 }
725 } else {
726 cerr << "Warning: Symmetry type " << sym->point << " not supported!" << endl;
727 }
728
729 if ( verbose & ( VERB_PROCESS | VERB_LABEL ) )
730 cout << "Views generated: " << n << endl << endl;
731
732 for ( v=view; v; v = v->next ) v->normalize();
733
734 if ( verbose & VERB_FULL ) {
735 cout << "View\tx\ty\tz\ta" << endl;
736 for ( v=view, i=1; v; v = v->next, i++ )
737 cout << i << tab << *v << endl;
738 cout << endl;
739 }
740
741 if ( temp_sym ) kill_symmetry(sym);
742
743 return view;
744 }
745
746 View* asymmetric_unit_views(Bsymmetry* sym, double theta_step, double phi_step, double alpha_step, int flag)
747 {
748 View* view = asymmetric_unit_views(sym, theta_step, phi_step, flag);
749
750 View* view2 = view_list_expand_angles(view, -M_PI, M_PI - alpha_step/2, alpha_step);
751
752 kill_list((char *) view, sizeof(View));
753
754 return view2;
755 }
756
769 View* side_views(Bsymmetry* sym, double side_ang, double theta_step, double phi_step)
770 {
771 if ( side_ang < 0 ) side_ang = -side_ang;
772 if ( theta_step <= 0 ) {
773 side_ang = 0;
774 theta_step = M_PI/180;
775 } else {
776 side_ang = theta_step*floor(side_ang/theta_step);
777 }
778 if ( phi_step <= 0 ) phi_step = M_PI_2;
779
780 int order = sym->op[0].order;
781 if ( order < 1 ) order = 1;
782
783 double phi, theta;
784 int n;
785 Euler euler;
786 View* view = NULL;
787 View* v = NULL;
788
789 if ( verbose & VERB_PROCESS ) {
790 cout << "Getting all the asymmetric unit side views for symmetry " << sym->label << endl;
791 cout << "Step size around equator: " << phi_step*180.0/M_PI << " degrees" << endl;
792 if ( side_ang ) {
793 cout << "Deviation from equator: " << side_ang*180.0/M_PI << " degrees" << endl;
794 cout << "Step size from equator: " << theta_step*180.0/M_PI << " degrees" << endl;
795 }
796 }
797
798 for ( n = 0, phi = -M_PI*1.0L/order; phi < M_PI*1.0L/order; phi += phi_step ) {
799 for ( theta = M_PI_2 - side_ang; theta <= M_PI_2 + side_ang; theta += theta_step ) {
800 v = (View *) add_item((char **) &view, sizeof(View));
801 euler = Euler(0, theta, phi);
802 *v = euler.view();
803 n++;
804 // cout << "theta=" << theta*180.0/M_PI << " phi=" << phi*180.0/M_PI << endl;
805 }
806 }
807
808 if ( verbose & VERB_PROCESS )
809 cout << "Number of views: " << n << endl << endl;
810
811 return view;
812 }
813
814 View* side_views(Bsymmetry* sym, double side_ang, double theta_step, double phi_step, double alpha_step)
815 {
816 View* view = side_views(sym, side_ang, theta_step, phi_step);
817
818 View* view2 = view_list_expand_angles(view, -M_PI, M_PI - alpha_step/2, alpha_step);
819
820 kill_list((char *) view, sizeof(View));
821
822 return view2;
823 }
824
834 int change_views_to_asymmetric_unit(Bsymmetry* sym, View* view)
835 {
836 if ( sym->point < 102 ) return 0;
837
838 View* v;
839
840 for ( v=view; v; v=v->next )
841 *v = find_asymmetric_unit_view(sym, *v);
842
843 return 0;
844 }
845
856 View find_asymmetric_unit_view(Bsymmetry* sym, View theview)
857 {
858 if ( sym->point < 102 ) return theview;
859 if ( sym->point >= 600 ) return theview;
860
861 View* v, bv(theview), tv;
862 View* view = symmetry_get_all_views(sym, theview);
863
864 int found(0);
865 double tol(1e-10);
866 double lim = tan(M_PI*1.0L/sym->op[0].order);
867
868 for ( v=view; v && !found; v=v->next )
869 if ( ( v->x() - tol >= 0 ) || ( v->x() + tol >= 0 && v->y() >= 0 ) ) {
870 tv.x(0); tv.y(0); tv.z(0);
871 if ( sym->point < 200 ) {
872 if ( sym->op[0].order == 2 ) {
873 tv = *v;
874 } else {
875 if ( fabs(v->y()) <= v->x()*lim + tol )
876 tv = *v;
877 }
878 } else if ( sym->point > 200 && sym->point < 300 ) {
879 if ( v->z() + tol >= 0 ) {
880 if ( sym->op[0].order == 2 ) {
881 tv = *v;
882 } else {
883 if ( fabs(v->y()) <= v->x()*lim + tol ) tv = *v;
884 }
885 }
886 } else if ( sym->point == 320 ) {
887 if ( fabs(v->y()) <= v->x() + tol && fabs(v->y()) <= v->z() + tol )
888 tv = *v;
889 } else if ( sym->point == 432 ) {
890 if ( fabs(v->y()) <= v->x() + tol && v->x() <= v->z() + tol )
891 tv = *v;
892 } else if ( sym->point == 532 ) {
893 if ( sym->label.contains("I90") ) {
894 if ( v->z() + tol >= 0 && fabs(v->y()) <= (v->z()/GOLDEN - v->x())/GOLDEN + tol )
895 tv = *v;
896 } else {
897 if ( v->z() + tol >= 0 && fabs(v->y()) <= v->z()/GOLDEN - v->x()*GOLDEN + tol )
898 tv = *v;
899 }
900 } else if ( sym->point >= 600 ) { // What is it for helical symmetry?
901 tv = theview;
902 }
903 if ( tv.vector_size() > 0.9 ) {
904 bv = tv;
905 found++;
906 }
907 }
908
909 if ( !found ) {
910 cerr << "ASU view not found: " << theview << endl;
911 // for ( v=view; v; v=v->next )
912 // cerr << *v << endl;
913 } else {
914 if ( verbose & VERB_STATS ) {
915 cout << "Old view:\t" << theview << endl;
916 cout << "New view:\t" << bv << endl;
917 }
918 }
919
920 kill_list((char *) view, sizeof(View));
921
922 bv.next = theview.next;
923
924 return bv;
925 }
926
939 View find_closest_symmetric_view(Bsymmetry* sym, View view_ref, View view)
940 {
941 if ( sym->point < 102 ) return view;
942 if ( sym->point >= 600 ) return view;
943
944 if ( verbose & VERB_DEBUG )
945 cout << "DEBUG find_closest_symmetric_view: " << sym->label << endl;
946
947 double r, rb(1e30);
948 View* v, bv(view);
949 View* viewsym = symmetry_get_all_views(sym, view);
950
951 for ( v=viewsym; v; v=v->next ) {
952 // r = v->residual(view_ref);
953 r = v->angle(view_ref);
954 if ( rb > r ) {
955 rb = r;
956 bv = *v;
957 }
958 }
959
960 kill_list((char *) viewsym, sizeof(View));
961
962 bv.next = view.next;
963
964 return bv;
965 }
966
972 View* reference_asymmetric_unit_views(Bsymmetry* sym)
973 {
974 View ref;
975
976 if ( sym->point < 200 ) {
977 ref[0] = 1;
978 ref[2] = 0;
979 } else if ( sym->point < 300 ) {
980 ref[0] = ref[2] = 1;
981 } else if ( sym->point == 320 ) {
982 ref[0] = ref[1] = cos(M_PI/8.0);
983 ref[2] = sin(M_PI/8.0);
984 } else if ( sym->point == 432 ) {
985 ref[0] = cos(M_PI/3.0);
986 ref[2] = sin(M_PI/3.0);
987 } else if ( sym->point == 532 ) {
988 if ( sym->label.contains("I90") ) {
989 ref[1] = 1;
990 ref[2] = GOLDEN + 1;
991 } else {
992 ref[0] = 1;
993 ref[2] = GOLDEN + 1;
994 }
995 } else if ( sym->point == 600 ) { // What is it for helical symmetry?
996 }
997
998 ref.normalize();
999
1000 View* rv = symmetry_get_all_views(sym, ref);
1001
1002 return rv;
1003 }
1004
1011 View random_symmetric_view(View& asu_view, Bsymmetry* sym)
1012 {
1013 View* v;
1014 View* view = symmetry_get_all_views(sym, asu_view);
1015
1016 long n = symmetry_order(sym);
1017
1018 long j, i(n*random()*0.99999L/get_rand_max());
1019
1020 for ( j=0, v=view; v && j<i; v=v->next, j++ ) ;
1021
1022 View vr(*v);
1023
1024 kill_list((char *) view, sizeof(View));
1025
1026 return vr;
1027 }
1028
1035 int test_asymmetric_unit_view(View theview, Bsymmetry* sym)
1036 {
1037 int i, n = 0;
1038 double a, amin = TWOPI;
1039
1040 View* rv = reference_asymmetric_unit_views(sym);
1041 View* v;
1042
1043 for ( i=0, v=rv; v; v=v->next, i++ ) {
1044 a = theview.angle(*v);
1045 if ( amin > a ) {
1046 amin = a;
1047 n = i;
1048 }
1049 }
1050
1051 kill_list((char *) rv, sizeof(View));
1052
1053 return n;
1054 }
1055
1069 float* sym_matrices_from_text_list(int nsym, char* symop, int line_len)
1070 {
1071 // Set up the symmetry operator matrix
1072 int i, j, k, l;
1073 float* mat = new float[nsym*12];
1074 for ( i=0; i<nsym*12; i++ ) mat[i] = 0;
1075
1076 char op[200];
1077 for ( i=0; i<nsym; i++ ) {
1078 if ( verbose & VERB_DEBUG )
1079 cout << "DEBUG sym_matrices_from_text_list: Symmetry operator " << i+1 << ":" << endl;
1080 k = 0;
1081 for ( j=0; j<3; j++ ) {
1082 l = 0;
1083 memset(op, 0, line_len);
1084 while ( k<line_len && symop[i*line_len+k] != ',' ) {
1085 op[l] = tolower(symop[i*line_len+k]);
1086 k++;
1087 l++;
1088 }
1089 op[l] = 0;
1090 if ( strstr(op,"-x") ) mat[i*12+4*j] = -1;
1091 else if ( strstr(op,"x") ) mat[i*12+4*j] = 1;
1092 if ( strstr(op,"-y") ) mat[i*12+4*j+1] = -1;
1093 else if ( strstr(op,"y") ) mat[i*12+4*j+1] = 1;
1094 if ( strstr(op,"-z") ) mat[i*12+4*j+2] = -1;
1095 else if ( strstr(op,"z") ) mat[i*12+4*j+2] = 1;
1096 if ( strstr(op,"1/2") ) mat[i*12+4*j+3] = 0.5;
1097 if ( strstr(op,"1/4") ) mat[i*12+4*j+3] = 0.25;
1098 if ( strstr(op,"3/4") ) mat[i*12+4*j+3] = 0.75;
1099 if ( strstr(op,"1/3") ) mat[i*12+4*j+3] = 1.0/3.0;
1100 if ( strstr(op,"2/3") ) mat[i*12+4*j+3] = 2.0/3.0;
1101 if ( strstr(op,"1/6") ) mat[i*12+4*j+3] = 1.0/6.0;
1102 if ( strstr(op,"5/6") ) mat[i*12+4*j+3] = 5.0/6.0;
1103 k++;
1104 if ( verbose & VERB_DEBUG )
1105 cout << "|" << mat[i*12+4*j] << " " << mat[i*12+4*j+1]
1106 << " " << mat[i*12+4*j+2] << "| |" << mat[i*12+4*j+3] << "|" << endl;
1107 }
1108 }
1109
1110 return 0;
1111 }
1112
1118 int sym_show_matrices(Bsymmetry* sym)
1119 {
1120 int i, nview = 1;
1121 for ( i=0; i<sym->n; i++ ) nview *= sym->op[i].order;
1122
1123 View ref;
1124 View* view = symmetry_get_all_views(sym, ref);
1125 View* v;
1126 Matrix3 mat;
1127
1128 cout << "\nSymmetry matrices (" << nview << "):" << endl;
1129 for ( i=1, v=view; v; i++, v=v->next ) {
1130 mat = v->matrix();
1131 cout << "Matrix " << i << ":" << endl;
1132 matrix3_show_hp(mat);
1133 }
1134 cout << endl;
1135
1136 kill_list((char *) view, sizeof(View));
1137
1138 return nview;
1139 }
1140
1146 int sym_show_operational_matrices(Bsymmetry* sym)
1147 {
1148 int i;
1149 Matrix3 mat;
1150
1151 for ( i=0; i<sym->n; i++ ) {
1152 mat = Matrix3(sym->op[i].axis, M_PI*2.0/sym->op[i].order);
1153 cout << "Operation " << i << ":" << endl;
1154 cout << "Axis and angle: " << sym->op[i].axis << " " << 360.0/sym->op[i].order << endl;
1155 cout << mat << endl;
1156 }
1157 cout << endl;
1158
1159 return sym->n;
1160 }
1161
1167 int sym_show_pdb_matrices(Bsymmetry* sym)
1168 {
1169 long nsym;
1170 int i, j, k;
1171 double t(0);
1172
1173 Matrix3* mat = symmetry_get_all_matrices(sym, nsym);
1174
1175 for ( i=0; i<nsym; i++ ) {
1176 for ( j=0; j<3; j++ ) {
1177 cout << "BIOMT" << j+1 << setw(4) << i+1 << setprecision(6);
1178 for ( k=0; k<3; k++ )
1179 cout << setw(10) << mat[i][j][k];
1180 cout << setprecision(6) << setw(15) << t << endl;
1181 }
1182 }
1183
1184 delete[] mat;
1185
1186 return sym->n;
1187 }
1188
1189
find_asymmetric_unit_view
View find_asymmetric_unit_view(Bsymmetry *sym, View theview)
Finds the corresponding view in the asymmetric unit.
Definition: symmetry.cpp:856
init_point_group_symmetry
Bsymmetry * init_point_group_symmetry(Bstring symmetry_string)
Sets up a symmetry structure from a string identifier.
Definition: symmetry.cpp:39
VERB_STATS
#define VERB_STATS
Definition: utilities.h:108
M_PI_2
#define M_PI_2
Definition: utilities.h:62
sym_show_operational_matrices
int sym_show_operational_matrices(Bsymmetry *sym)
Show symmetry matrices associated with each symmetry operator.
Definition: symmetry.cpp:1146
kill_symmetry
int kill_symmetry(Bsymmetry *sym)
Deallocates a symmetry structure.
Definition: symmetry.cpp:207
Vector3::normalize
double normalize()
Definition: Vector3.h:236
Euler
Definition: Euler.h:28
Bstring::substr
Bstring substr(long start, long len)
Definition: Bstring.cpp:324
View::next
View * next
Definition: View.h:28
Bsymmetry::n
int n
Definition: symmetry.h:42
verbose
int verbose
sym_show_pdb_matrices
int sym_show_pdb_matrices(Bsymmetry *sym)
Show PDB format symmetry matrices associated with each symmetry operator.
Definition: symmetry.cpp:1167
symmetry.h
Header file for general symmetry functions.
utilities.h
Header file for general utilities.
VERB_DEBUG
#define VERB_DEBUG
Definition: utilities.h:112
View::z
double z()
Definition: View.h:94
kill_list
long kill_list(char *list, unsigned long size)
Frees all the items in a linked list.
Definition: linked_list.cpp:214
add_item
char * add_item(char **list, unsigned long size)
Adds an item to a linked list.
Definition: linked_list.cpp:26
Matrix3
Definition: Matrix3.h:17
Bstring::length
long length() const
Definition: Bstring.cpp:263
symmetry_helical_label
string symmetry_helical_label(double helix_rise, double helix_angle, int dyad_axis, int cyclic, double seam_shift)
Returns the label for helical symmetry.
Definition: symmetry.cpp:280
GOLDEN
#define GOLDEN
Definition: utilities.h:81
random_symmetric_view
View random_symmetric_view(View &asu_view, Bsymmetry *sym)
Returns a randomly picked symmetry view.
Definition: symmetry.cpp:1011
Quaternion
Definition: Quaternion.h:25
VERB_PROCESS
#define VERB_PROCESS
Definition: utilities.h:107
View::y
double y()
Definition: View.h:93
Bsymop::angle
double angle
Definition: symmetry.h:27
View::vector_size
double vector_size()
Definition: View.h:103
asymmetric_unit_views
View * asymmetric_unit_views(Bsymmetry *sym, double theta_step, double phi_step, int flag)
Initializes a well-distributed set of views in an asymmetric unit.
Definition: symmetry.cpp:570
M_PI_4
#define M_PI_4
Definition: utilities.h:65
Bstring::contains
bool contains(const Bstring &s)
Definition: Bstring.cpp:584
Bstring::no_space
Bstring no_space()
Definition: Bstring.cpp:332
M_PI
#define M_PI
Definition: utilities.h:59
linked_list.h
Header file for generalized linked list functions.
Bsymmetry::point
int point
Definition: symmetry.h:39
sym_show_matrices
int sym_show_matrices(Bsymmetry *sym)
Show symmetry matrices.
Definition: symmetry.cpp:1118
matrix3_show_hp
int matrix3_show_hp(Matrix3 &mat)
Print out a matrix.
Definition: Matrix3.cpp:31
view_symmetry_reference
View view_symmetry_reference(Bsymmetry *sym)
Returns an asymmetric unit reference point.
Definition: symmetry.cpp:315
side_views
View * side_views(Bsymmetry *sym, double side_ang, double theta_step, double phi_step)
Initializes a set of views around the z-axis for helical projection.
Definition: symmetry.cpp:769
symmetry_get_axes
Vector3< double > * symmetry_get_axes(Bsymmetry *sym, long &nax)
Get all symmetry axes.
Definition: symmetry.cpp:379
reference_asymmetric_unit_views
View * reference_asymmetric_unit_views(Bsymmetry *sym)
Returns a reference view for each asymmetric unit.
Definition: symmetry.cpp:972
symmetry_get_all_matrices
Matrix3 * symmetry_get_all_matrices(Bsymmetry *sym, long &nsym)
Get all symmetry-related views of one given view.
Definition: symmetry.cpp:520
Bsymop::order
int order
Definition: symmetry.h:26
Bsymop::shift
double shift
Definition: symmetry.h:28
View::normalize
double normalize()
Definition: View.h:106
sym_matrices_from_text_list
float * sym_matrices_from_text_list(int nsym, char *symop, int line_len)
Calculates symmetry matrices from a list of strings.
Definition: symmetry.cpp:1069
Bstring::c_str
const char * c_str()
Definition: Bstring.h:70
get_rand_max
long get_rand_max()
Finds the maximum random number for a system.
Definition: random_numbers.cpp:22
Bsymmetry::label
Bstring label
Definition: symmetry.h:41
Bsymmetry
Definition: symmetry.h:38
change_views_to_asymmetric_unit
int change_views_to_asymmetric_unit(Bsymmetry *sym, View *view)
Change the views to those in the asymmetric unit.
Definition: symmetry.cpp:834
random_numbers.h
Header file for functions for creating random images.
Bstring
Definition: Bstring.h:29
find_closest_symmetric_view
View find_closest_symmetric_view(Bsymmetry *sym, View view_ref, View view)
Finds the closest symmetric match between two views.
Definition: symmetry.cpp:939
Bsymop
Definition: symmetry.h:24
Vector3< double >
View::angle
double angle()
Definition: View.h:95
View
Definition: View.h:26
Euler::view
View view()
Definition: Euler.h:62
Bstring::integer
long integer()
Definition: Bstring.cpp:539
test_asymmetric_unit_view
int test_asymmetric_unit_view(View theview, Bsymmetry *sym)
Returns an asymmetric unit index number.
Definition: symmetry.cpp:1035
Bsymmetry::op
Bsymop * op
Definition: symmetry.h:43
view_list_expand_angles
View * view_list_expand_angles(View *views, double amin, double amax, double astep)
Expands each view to several views with different rotation angles.
Definition: View.cpp:435
symmetry_rotate_to_axis
Matrix3 symmetry_rotate_to_axis(Bsymmetry *sym, long axis, long axis_flag)
Rotation matrix to orient a symmetry axis on the z axis.
Definition: symmetry.cpp:347
symmetry_order
int symmetry_order(Bsymmetry *sym)
Returns the symmetry order.
Definition: symmetry.cpp:301
VERB_FULL
#define VERB_FULL
Definition: utilities.h:109
View::x
double x()
Definition: View.h:92
VERB_LABEL
#define VERB_LABEL
Definition: utilities.h:106
Bsymop::axis
Vector3< double > axis
Definition: symmetry.h:25
TWOPI
#define TWOPI
Definition: utilities.h:68
error_show
int error_show(string message, string file, int line)
Displays the error with file and line reference.
Definition: utilities.cpp:755
tab
ostream & tab(ostream &out)
Definition: utilities.cpp:21
symmetry_get_all_views
View * symmetry_get_all_views(Bsymmetry *sym, View asu_view)
Get all symmetry-related views of one given view.
Definition: symmetry.cpp:448
Euler.h
Euler object.
symmetry_clean_pointgroup
Bstring symmetry_clean_pointgroup(Bstring &symmetry_string)
Corrects an existing point group string.
Definition: symmetry.cpp:226