1 /* Copyright (C) 2017 Atsushi Togo */
2 /* All rights reserved. */
3 
4 /* This file is part of spglib. */
5 
6 /* Redistribution and use in source and binary forms, with or without */
7 /* modification, are permitted provided that the following conditions */
8 /* are met: */
9 
10 /* * Redistributions of source code must retain the above copyright */
11 /*   notice, this list of conditions and the following disclaimer. */
12 
13 /* * Redistributions in binary form must reproduce the above copyright */
14 /*   notice, this list of conditions and the following disclaimer in */
15 /*   the documentation and/or other materials provided with the */
16 /*   distribution. */
17 
18 /* * Neither the name of the spglib project nor the names of its */
19 /*   contributors may be used to endorse or promote products derived */
20 /*   from this software without specific prior written permission. */
21 
22 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
23 /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
24 /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS */
25 /* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE */
26 /* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, */
27 /* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, */
28 /* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */
29 /* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER */
30 /* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT */
31 /* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN */
32 /* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE */
33 /* POSSIBILITY OF SUCH DAMAGE. */
34 
35 #include <stdlib.h>
36 #include "cell.h"
37 #include "determination.h"
38 #include "primitive.h"
39 #include "refinement.h"
40 #include "spacegroup.h"
41 
42 #include "debug.h"
43 
44 #define REDUCE_RATE_OUTER 0.9
45 #define NUM_ATTEMPT_OUTER 10
46 #define REDUCE_RATE 0.95
47 #define ANGLE_REDUCE_RATE 0.95
48 #define NUM_ATTEMPT 20
49 
50 static DataContainer * get_spacegroup_and_primitive(const Cell * cell,
51                                                     const int hall_number,
52                                                     const double symprec,
53                                                     const double angle_symprec);
54 
det_determine_all(const Cell * cell,const int hall_number,const double symprec,const double angle_symprec)55 DataContainer * det_determine_all(const Cell * cell,
56                                   const int hall_number,
57                                   const double symprec,
58                                   const double angle_symprec)
59 {
60   int attempt;
61   double tolerance;
62   DataContainer *container;
63 
64   container = NULL;
65 
66   if (hall_number < 0 || hall_number > 530) {
67     return NULL;
68   }
69 
70   tolerance = symprec;
71   for (attempt = 0; attempt < NUM_ATTEMPT_OUTER; attempt++) {
72     if ((container = get_spacegroup_and_primitive(cell,
73                                                   hall_number,
74                                                   tolerance,
75                                                   angle_symprec)) != NULL) {
76       if ((container->exact_structure = ref_get_exact_structure_and_symmetry(
77              container->spacegroup,
78              container->primitive->cell,
79              cell,
80              container->primitive->mapping_table,
81              container->primitive->tolerance)) != NULL) {
82         goto found;
83       }
84       warning_print("spglib: ref_get_exact_structure_and_symmetry failed.");
85       warning_print(" (line %d, %s).\n", __LINE__, __FILE__);
86       det_free_container(container);
87       container = NULL;
88     }
89     tolerance *= REDUCE_RATE_OUTER;
90   }
91 
92 found:
93   return container;
94 }
95 
det_free_container(DataContainer * container)96 void det_free_container(DataContainer * container)
97 {
98   if (container != NULL) {
99     if (container->spacegroup != NULL) {
100       free(container->spacegroup);
101       container->spacegroup = NULL;
102     }
103     if (container->primitive != NULL) {
104       prm_free_primitive(container->primitive);
105       container->primitive = NULL;
106     }
107     if (container->exact_structure != NULL) {
108       ref_free_exact_structure(container->exact_structure);
109       container->exact_structure = NULL;
110     }
111     free(container);
112   }
113 }
114 
115 /* NULL is returned if failed */
get_spacegroup_and_primitive(const Cell * cell,const int hall_number,const double symprec,const double angle_symprec)116 static DataContainer * get_spacegroup_and_primitive(const Cell * cell,
117                                                     const int hall_number,
118                                                     const double symprec,
119                                                     const double angle_symprec)
120 {
121   int attempt;
122   double tolerance, angle_tolerance;
123   DataContainer *container;
124 
125   debug_print("get_spacegroup_and_primitive (tolerance = %f):\n", symprec);
126 
127   container = NULL;
128 
129   if ((container = (DataContainer*) malloc(sizeof(DataContainer))) == NULL) {
130     warning_print("spglib: Memory could not be allocated.");
131     return NULL;
132   }
133 
134   container->primitive = NULL;
135   container->spacegroup = NULL;
136   container->exact_structure = NULL;
137 
138   tolerance = symprec;
139   angle_tolerance = angle_symprec;
140 
141   for (attempt = 0; attempt < NUM_ATTEMPT; attempt++) {
142     if ((container->primitive = prm_get_primitive(cell,
143                                                   tolerance,
144                                                   angle_tolerance)) != NULL) {
145 
146       debug_print("[line %d, %s]\n", __LINE__, __FILE__);
147       debug_print("primitive lattice\n");
148       debug_print_matrix_d3(container->primitive->cell->lattice);
149 
150       if ((container->spacegroup = spa_search_spacegroup(
151              container->primitive,
152              hall_number,
153              container->primitive->tolerance,
154              container->primitive->angle_tolerance)) != NULL) {
155         goto found;
156       }
157 
158       prm_free_primitive(container->primitive);
159       container->primitive = NULL;
160     }
161 
162     warning_print("spglib: Attempt %d tolerance = %f failed.",
163                   attempt, tolerance);
164     warning_print(" (line %d, %s).\n", __LINE__, __FILE__);
165 
166     tolerance *= REDUCE_RATE;
167     if (angle_tolerance > 0) {
168       angle_tolerance *= ANGLE_REDUCE_RATE;
169     }
170   }
171 
172   det_free_container(container);
173   container = NULL;
174 
175   return NULL;
176 
177 found:
178   return container;
179 }
180