1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
//
// GENERATED FILE
//
use super::*;
use f2rust_std::*;
pub const LBCELL: i32 = -5;
const MSGLEN: i32 = 256;
const MXLOOP: i32 = 1000;
//$Procedure ZZGFSOLVX ( Private --- GF, event finding routine )
pub fn ZZGFSOLVX(
UDFUNS: fn(&mut f64, &mut f64, &mut Context) -> f2rust_std::Result<()>,
UDFUNB: fn(
fn(&mut f64, &mut f64, &mut Context) -> f2rust_std::Result<()>,
&mut f64,
&mut bool,
&mut Context,
) -> f2rust_std::Result<()>,
UDSTEP: fn(&mut f64, &mut f64, &mut Context) -> f2rust_std::Result<()>,
UDREFN: fn(f64, f64, bool, bool, &mut f64) -> (),
BAIL: bool,
UDBAIL: fn() -> bool,
CSTEP: bool,
STEP: f64,
START: f64,
FINISH: f64,
TOL: f64,
RPT: bool,
UDREPU: fn(f64, f64, f64, &mut Context) -> f2rust_std::Result<()>,
RESULT: &mut [f64],
ctx: &mut Context,
) -> f2rust_std::Result<()> {
let mut RESULT = DummyArrayMut::new(RESULT, LBCELL..);
let mut BEGIN: f64 = 0.0;
let mut CURTIM: f64 = 0.0;
let mut DIFF: f64 = 0.0;
let mut PRVDIF: f64 = 0.0;
let mut SVDTIM: f64 = 0.0;
let mut T: f64 = 0.0;
let mut T1: f64 = 0.0;
let mut T2: f64 = 0.0;
let mut TIMEST: f64 = 0.0;
let mut TRNSTN: f64 = 0.0;
let mut CURSTE: bool = false;
let mut INSTAT: bool = false;
let mut S: bool = false;
let mut STATE1: bool = false;
let mut SAVST: bool = false;
let mut L1: bool = false;
let mut L2: bool = false;
let mut CONTXT = [b' '; MSGLEN as usize];
let mut NLOOP: i32 = 0;
//
// SPICELIB functions
//
//
// Local parameters
//
//
// Local variables
//
//
// The maximum number of search loop iterations to execute.
// The default refinement method is bisection, a very slow
// method to convergence. Since 2**1000 ~ 10**301,
// 1000 loop iterations represents enough effort to assume
// either the search will not converge or that the refinement
// function operates slower than would bisection, in which
// case the user should use the default GFREFN function.
//
//
// Standard SPICE error handling.
//
if RETURN(ctx) {
return Ok(());
}
CHKIN(b"ZZGFSOLVX", ctx)?;
//
// Check the convergence tolerance.
//
if (TOL <= 0.0) {
SETMSG(b"Tolerance must be positive but was #.", ctx);
ERRDP(b"#", TOL, ctx);
SIGERR(b"SPICE(INVALIDTOLERANCE)", ctx)?;
CHKOUT(b"ZZGFSOLVX", ctx)?;
return Ok(());
}
//
// Make sure that START is not greater than FINISH. Signal an
// error for START > FINISH.
//
if (START > FINISH) {
SETMSG(b"Bad time interval result, START > FINISH.", ctx);
SIGERR(b"SPICE(BADTIMECASE)", ctx)?;
CHKOUT(b"ZZGFSOLVX", ctx)?;
return Ok(());
}
//
// If active, update the progress reporter.
//
if RPT {
UDREPU(START, FINISH, START, ctx)?;
}
//
// This algorithm determines those intervals when a given state
// is observed to occur within a specified search interval.
//
// Pairs of times are recorded. The first member of each pair
// denotes the time when the system changes to the state of
// interest. The second denotes a transition out of that state.
//
// If the system is in the state of interest at the beginning of
// the interval, the beginning of the time interval will be
// recorded. This may or may not be a transition point.
//
// Similarly if the system is in the state of interest at the end
// of the interval, the end of the interval will be recorded.
// Again, this may or may not be a transition point.
//
//
// Initially the current time is the beginning of the search
// interval.
//
CURTIM = START;
//
// Determine if the state at the current time satisfies some
// constraint. This constraint may indicate only existence of
// a state.
//
UDFUNB(UDFUNS, &mut CURTIM, &mut CURSTE, ctx)?;
if FAILED(ctx) {
CHKOUT(b"ZZGFSOLVX", ctx)?;
return Ok(());
}
//
// If the system is in the state of interest, record the initial
// time of the search interval.
//
if CURSTE {
INSTAT = true;
BEGIN = CURTIM;
} else {
INSTAT = false;
}
//
// If the step size is constant, use the value supplied.
//
if CSTEP {
TIMEST = STEP;
}
//
// Save the current time and state somewhere.
//
SVDTIM = CURTIM;
SAVST = CURSTE;
//
// Once initializations have been performed keep working
// until the search interval has been exhausted.
//
// While time remains in the search interval.
//
while (SVDTIM < FINISH) {
//
// Using the current window and internally stored
// information about the current state, select a new current
// time.
//
if !CSTEP {
UDSTEP(&mut CURTIM, &mut TIMEST, ctx)?;
if FAILED(ctx) {
CHKOUT(b"ZZGFSOLVX", ctx)?;
return Ok(());
}
}
//
// Add the time step to the current time. Make sure that the
// time does not move beyond the end of the search interval.
//
CURTIM = intrinsics::DMIN1(&[(CURTIM + TIMEST), FINISH]);
//
// Compute the state at time CURTIM.
//
UDFUNB(UDFUNS, &mut CURTIM, &mut CURSTE, ctx)?;
if FAILED(ctx) {
CHKOUT(b"ZZGFSOLVX", ctx)?;
return Ok(());
}
//
// While the state remains unchanged and the interval is not
// completely searched ...
//
while ((SAVST == CURSTE) && (SVDTIM < FINISH)) {
//
// First check for an interrupt signal if checking is enabled.
//
if BAIL {
if UDBAIL() {
CHKOUT(b"ZZGFSOLVX", ctx)?;
return Ok(());
}
}
//
// Report the current time to the monitoring utility, if
// appropriate.
//
if RPT {
UDREPU(START, FINISH, SVDTIM, ctx)?;
}
//
// Save the current time and state somewhere.
//
SVDTIM = CURTIM;
SAVST = CURSTE;
//
// Compute a new current time so that we will not step
// past the end of the interval. This time will be
// based on:
//
// 1. The kind of event we are looking for.
// 2. The objects and observer class.
// 3. Transition times already found.
// 4. A minimum time step allowed.
//
if !CSTEP {
UDSTEP(&mut CURTIM, &mut TIMEST, ctx)?;
if FAILED(ctx) {
CHKOUT(b"ZZGFSOLVX", ctx)?;
return Ok(());
}
}
CURTIM = intrinsics::DMIN1(&[(CURTIM + TIMEST), FINISH]);
//
// Compute the current state
//
UDFUNB(UDFUNS, &mut CURTIM, &mut CURSTE, ctx)?;
if FAILED(ctx) {
CHKOUT(b"ZZGFSOLVX", ctx)?;
return Ok(());
}
//
// Loop back to see if the state has changed.
//
}
//
// If we have detected a state change and not merely run out
// of the search interval...
//
if (SAVST != CURSTE) {
//
// Call the previous state STATE1
// Call the current state STATE2
//
// Call the time at state STATE1, T1
// Call the time at state STATE2, T2
//
// Save the current time.
//
STATE1 = SAVST;
T1 = SVDTIM;
T2 = CURTIM;
//
// Set the states at T1 and T2 for use by the refinement
// function, in case the caller has passed in a function
// that uses them.
//
L1 = SAVST;
L2 = CURSTE;
//
// Make sure that T1 is not greater than T2. Signal an
// error for T1 > T2.
//
if (T1 > T2) {
SETMSG(b"Bad time interval result, T1 > T2.", ctx);
SIGERR(b"SPICE(BADTIMECASE)", ctx)?;
CHKOUT(b"ZZGFSOLVX", ctx)?;
return Ok(());
}
SVDTIM = CURTIM;
SAVST = CURSTE;
//
// T1 and T2 bracket the time of transition. Squeeze this
// interval down until it is less than some tolerance in
// length. Do it as described below...
//
// Loop while the difference between the times T1 and T2
// exceeds a specified tolerance, and while the magnitude
// of the difference is decreasing from one loop iteration
// to the next.
//
PRVDIF = DPMAX();
DIFF = TOUCHD(f64::abs((T2 - T1)));
NLOOP = 0;
while ((DIFF > TOL) && (DIFF < PRVDIF)) {
NLOOP = (NLOOP + 1);
//
// This loop count error exists to catch pathologies
// in the refinement function. The default bisection
// refinement will converge before 1000 iterations if
// a convergence is numerically possible. Any other
// refinement function should require fewer iterations
// compared to bisection. If not, the user should
// probably use bisection.
//
if (NLOOP >= MXLOOP) {
SETMSG(b"Loop run exceeds maximum loop count. Unable to converge to TOL value #1 within MXLOOP value #2 iterations.", ctx);
ERRDP(b"#1", TOL, ctx);
ERRINT(b"#2", MXLOOP, ctx);
SIGERR(b"SPICE(NOCONVERG)", ctx)?;
CHKOUT(b"ZZGFSOLVX", ctx)?;
return Ok(());
}
if BAIL {
if UDBAIL() {
CHKOUT(b"ZZGFSOLVX", ctx)?;
return Ok(());
}
}
//
// Select a time T, between T1 and T2 (possibly based on the
// values of L1 and L2).
//
UDREFN(T1, T2, L1, L2, &mut T);
//
// Check for an error signal. The default refinement
// routine, GFREFN, does not include error checks.
//
if FAILED(ctx) {
CHKOUT(b"ZZGFSOLVX", ctx)?;
return Ok(());
}
//
// Check whether T is between T1 and T2. If
// not then assume that we have gone as far as
// we can in refining our estimate of the transition
// point. Set T1 and T2 equal to T.
//
T = BRCKTD(T, T1, T2);
if (T == T1) {
T2 = T;
} else if (T == T2) {
T1 = T;
} else {
//
// Compute the state time T. If this state, S,
// equals STATE1, set T1 to T, otherwise set
// T2 to T.
//
UDFUNB(UDFUNS, &mut T, &mut S, ctx)?;
if (S == STATE1) {
T1 = T;
L1 = S;
} else {
T2 = T;
L2 = S;
}
}
//
// Update PRVDIF and DIFF for the next loop termination
// test.
//
PRVDIF = DIFF;
DIFF = TOUCHD(f64::abs((T2 - T1)));
}
//
// Let TRNSTN be the midpoint of [T1, T2]. Record this
// time as marking the transition from STATE1 to STATE2.
//
TRNSTN = BRCKTD(((T1 + T2) * 0.5), T1, T2);
//
// In state-of-interest or not?
//
if INSTAT {
//
// We were in the state of interest, TRNSTN marks the
// point in time when the state changed to "not of
// interest" We need to record the interval from BEGIN to
// FINISH and note that we are no longer in the state of
// interest.
//
//
// Add an interval starting at BEGIN and ending at TRNSTN
// to the result window.
//
fstr::assign(&mut CONTXT, b"Adding interval [BEGIN,TRNSTN] to RESULT. TRNSTN represents time of passage out of the state-of-interest.");
ZZWNINSD(BEGIN, TRNSTN, &CONTXT, RESULT.as_slice_mut(), ctx)?;
} else {
//
// We were not in the state of interest. As a result
// TRNSTN marks the point where we are changing to
// the state of interest. Note that we have transitioned
// to the state of interest and record the time at
// which the transition occurred.
//
BEGIN = TRNSTN;
}
//
// A transition occurred either from from in-state to
// out-of-state or the inverse. Reverse the value of the
// INSTAT flag to signify the transition event.
//
INSTAT = !INSTAT;
//
// That's it for this detection of state change.
//
}
//
// Continue if there is more time in the search interval.
//
}
//
// Check if in-state at this time (FINISH). If so record the
// interval.
//
if INSTAT {
//
// Add an interval starting at BEGIN and ending at FINISH to the
// window.
//
fstr::assign(&mut CONTXT, b"Adding interval [BEGIN,FINISH] to RESULT. FINISH represents end of the search interval.");
ZZWNINSD(BEGIN, FINISH, &CONTXT, RESULT.as_slice_mut(), ctx)?;
}
//
// If active, update the progress reporter before exiting this
// routine.
//
if RPT {
UDREPU(START, FINISH, FINISH, ctx)?;
}
//
// Check-out then return.
//
CHKOUT(b"ZZGFSOLVX", ctx)?;
Ok(())
}