1use crate::constraints::EvalMode;
5use crate::context::PackContext;
6use crate::gencan::GencanWorkspace;
7use crate::initial::restmol;
8use crate::random::uniform01;
9use molrs::types::F;
10use rand::Rng;
11
12pub struct MoveBadConfig<'a> {
13 pub movefrac: F,
14 pub maxmove_per_type: &'a [usize],
15 pub movebadrandom: bool,
16 pub gencan_maxit: usize,
17}
18
19pub fn movebad(
22 x: &mut [F],
23 sys: &mut PackContext,
24 precision: F,
25 cfg: &MoveBadConfig<'_>,
26 rng: &mut impl Rng,
27 workspace: &mut GencanWorkspace,
28) {
29 let ntotat = sys.ntotat;
31 for icart in 0..ntotat {
32 sys.fdist_atom[icart] = 0.0;
33 sys.frest_atom[icart] = 0.0;
34 }
35
36 sys.move_flag = true;
40 sys.work.radiuswork.copy_from_slice(&sys.radius);
41 for i in 0..sys.ntotat {
42 sys.set_radius(i, sys.radius_ini[i]);
43 }
44 sys.evaluate(x, EvalMode::FOnly, None);
45 sys.move_flag = false;
46
47 let ntotmol = sys.ntotmol;
48
49 let mut icart_offset = 0usize;
50 for itype in 0..sys.ntype {
51 if !sys.comptype[itype] {
52 icart_offset += sys.nmols[itype] * sys.natoms[itype];
53 continue;
54 }
55
56 let nmols_itype = sys.nmols[itype];
57 let natoms_itype = sys.natoms[itype];
58
59 sys.work.fmol.clear();
61 sys.work.fmol.resize(nmols_itype, 0.0);
62 let fmol = &mut sys.work.fmol;
63 let mut nbad = 0usize;
64 let mut icart = icart_offset;
65 for score in fmol.iter_mut().take(nmols_itype) {
66 let mut fdist_mol = 0.0 as F;
67 let mut frest_mol = 0.0 as F;
68 for _ in 0..natoms_itype {
69 fdist_mol = fdist_mol.max(sys.fdist_atom[icart]);
70 frest_mol = frest_mol.max(sys.frest_atom[icart]);
71 icart += 1;
72 }
73 if fdist_mol > precision || frest_mol > precision {
74 nbad += 1;
75 *score = fdist_mol + frest_mol;
76 }
77 }
78
79 if nbad == 0 {
80 icart_offset += nmols_itype * natoms_itype;
81 continue;
82 }
83
84 let frac = (nbad as F / nmols_itype as F).min(cfg.movefrac);
85 let nmove_base = (nmols_itype as F * frac) as isize;
86 let nmove = usize::min(
87 cfg.maxmove_per_type[itype],
88 isize::max(nmove_base, 1) as usize,
89 );
90
91 let mflash = 1 + nmols_itype / 10;
93 sys.work.flash_ind.clear();
94 sys.work.flash_ind.extend(0..nmols_itype);
95 flash1(fmol, mflash, &mut sys.work.flash_ind, &mut sys.work.flash_l);
96
97 let mol_base: usize = {
105 let mut base = 0usize;
106 for it in 0..itype {
107 if sys.comptype[it] {
108 base += sys.nmols[it];
109 }
110 }
111 base
112 };
113
114 let move_pairs: Vec<(usize, usize)> = (0..nmove)
117 .map(|k| {
118 let ibad_mol = sys.work.flash_ind[nmols_itype - 1 - k];
119 let igood_mol = sys.work.flash_ind
120 [(uniform01(rng) * nmols_itype as F * frac) as usize % nmols_itype.max(1)];
121 (ibad_mol, igood_mol)
122 })
123 .collect();
124
125 for &(ibad_mol, igood_mol) in &move_pairs {
126 let ilubar_bad = (mol_base + ibad_mol) * 3;
127 let ilugan_bad = ntotmol * 3 + (mol_base + ibad_mol) * 3;
128 let ilubar_good = (mol_base + igood_mol) * 3;
129 let ilugan_good = ntotmol * 3 + (mol_base + igood_mol) * 3;
130
131 let dmax = sys.dmax[itype];
132 if cfg.movebadrandom {
133 x[ilubar_bad] = sys.sizemin[0] + uniform01(rng) * (sys.sizemax[0] - sys.sizemin[0]);
134 x[ilubar_bad + 1] =
135 sys.sizemin[1] + uniform01(rng) * (sys.sizemax[1] - sys.sizemin[1]);
136 x[ilubar_bad + 2] =
137 sys.sizemin[2] + uniform01(rng) * (sys.sizemax[2] - sys.sizemin[2]);
138 } else {
139 x[ilubar_bad] = x[ilubar_good] - 0.3 * dmax + 0.6 * uniform01(rng) * dmax;
141 x[ilubar_bad + 1] = x[ilubar_good + 1] - 0.3 * dmax + 0.6 * uniform01(rng) * dmax;
142 x[ilubar_bad + 2] = x[ilubar_good + 2] - 0.3 * dmax + 0.6 * uniform01(rng) * dmax;
143 }
144
145 x[ilugan_bad] = x[ilugan_good];
147 x[ilugan_bad + 1] = x[ilugan_good + 1];
148 x[ilugan_bad + 2] = x[ilugan_good + 2];
149
150 restmol(
152 itype,
153 ilubar_bad,
154 x,
155 sys,
156 precision,
157 cfg.gencan_maxit,
158 true,
159 workspace,
160 );
161 }
162
163 icart_offset += nmols_itype * natoms_itype;
164 }
165
166 sys.evaluate(x, EvalMode::FOnly, None);
167 for i in 0..sys.ntotat {
168 sys.set_radius(i, sys.work.radiuswork[i]);
169 }
170}
171
172pub fn flash1(a: &mut [F], m: usize, ind: &mut [usize], l_buf: &mut Vec<usize>) {
178 let n = a.len();
179 if n <= 1 {
180 return;
181 }
182 debug_assert_eq!(ind.len(), n);
183
184 let anmin = a.iter().copied().fold(F::INFINITY, F::min);
185 let nmax_idx = a
186 .iter()
187 .enumerate()
188 .max_by(|(_, x), (_, y)| x.total_cmp(y))
189 .map(|(i, _)| i)
190 .unwrap_or(0);
191
192 if a[0] == a[nmax_idx] {
193 return; }
195
196 let c1 = (m as F - 1.0) / (a[nmax_idx] - anmin);
197 l_buf.clear();
198 l_buf.resize(m, 0);
199 let l = l_buf;
200
201 for ai in a.iter().take(n) {
202 let k = (c1 * (*ai - anmin)) as usize;
203 let k = k.min(m - 1);
204 l[k] += 1;
205 }
206 for k in 1..m {
207 l[k] += l[k - 1];
208 }
209
210 a.swap(nmax_idx, 0);
212 ind.swap(nmax_idx, 0);
213
214 let mut nmove = 0usize;
216 let mut j = 0usize;
217 let mut k = m;
218
219 while nmove < n - 1 {
220 while j >= l[k - 1] {
221 j += 1;
222 if j >= n {
223 break;
224 }
225 k = (c1 * (a[j] - anmin)) as usize;
226 k = k.min(m - 1) + 1;
227 }
228 if j >= n {
229 break;
230 }
231 let mut flash = a[j];
232 let mut iflash = ind[j];
233 while j != l[k - 1] {
234 k = (c1 * (flash - anmin)) as usize;
235 k = k.min(m - 1);
236 let lk = l[k] - 1;
237 l[k] -= 1;
238 let hold = a[lk];
239 let ihold = ind[lk];
240 a[lk] = flash;
241 ind[lk] = iflash;
242 flash = hold;
243 iflash = ihold;
244 nmove += 1;
245 k = (c1 * (flash - anmin)) as usize;
247 k = k.min(m - 1) + 1;
248 }
249 }
250
251 let mut i = n as isize - 2;
253 while i >= 1 {
254 let iu = i as usize;
255 if a[iu + 1] < a[iu] {
256 let hold = a[iu];
257 let ihold = ind[iu];
258 let mut j = iu;
259 while j + 1 < n && a[j + 1] < hold {
260 a[j] = a[j + 1];
261 ind[j] = ind[j + 1];
262 j += 1;
263 }
264 a[j] = hold;
265 ind[j] = ihold;
266 }
267 i -= 1;
268 }
269}