1import numpy as np
2
3from yt.testing import assert_array_equal, fake_amr_ds
4
5# We use morton indices in this test because they are single floating point
6# values that uniquely identify each cell.  That's a convenient way to compare
7# inclusion in set operations, since there are no duplicates.
8
9
10def test_boolean_spheres_no_overlap():
11    r"""Test to make sure that boolean objects (spheres, no overlap)
12    behave the way we expect.
13
14    Test non-overlapping spheres. This also checks that the original spheres
15    don't change as part of constructing the booleans.
16    """
17    ds = fake_amr_ds()
18    sp1 = ds.sphere([0.25, 0.25, 0.25], 0.15)
19    sp2 = ds.sphere([0.75, 0.75, 0.75], 0.15)
20    # Store the original indices
21    i1 = sp1["index", "morton_index"]
22    i1.sort()
23    i2 = sp2["index", "morton_index"]
24    i2.sort()
25    ii = np.concatenate((i1, i2))
26    ii.sort()
27    # Make some booleans
28    bo1 = sp1 & sp2
29    bo2 = sp1 - sp2
30    bo3 = sp1 | sp2  # also works with +
31    bo4 = ds.union([sp1, sp2])
32    bo5 = ds.intersection([sp1, sp2])
33    # This makes sure the original containers didn't change.
34    new_i1 = sp1["index", "morton_index"]
35    new_i1.sort()
36    new_i2 = sp2["index", "morton_index"]
37    new_i2.sort()
38    assert_array_equal(new_i1, i1)
39    assert_array_equal(new_i2, i2)
40    # Now make sure the indices also behave as we expect.
41    empty = np.array([])
42    assert_array_equal(bo1["index", "morton_index"], empty)
43    assert_array_equal(bo5["index", "morton_index"], empty)
44    b2 = bo2["index", "morton_index"]
45    b2.sort()
46    assert_array_equal(b2, i1)
47    b3 = bo3["index", "morton_index"]
48    b3.sort()
49    assert_array_equal(b3, ii)
50    b4 = bo4["index", "morton_index"]
51    b4.sort()
52    assert_array_equal(b4, ii)
53    bo6 = sp1 ^ sp2
54    b6 = bo6["index", "morton_index"]
55    b6.sort()
56    assert_array_equal(b6, np.setxor1d(i1, i2))
57
58
59def test_boolean_spheres_overlap():
60    r"""Test to make sure that boolean objects (spheres, overlap)
61    behave the way we expect.
62
63    Test overlapping spheres.
64    """
65    ds = fake_amr_ds()
66    sp1 = ds.sphere([0.45, 0.45, 0.45], 0.15)
67    sp2 = ds.sphere([0.55, 0.55, 0.55], 0.15)
68    # Get indices of both.
69    i1 = sp1["index", "morton_index"]
70    i2 = sp2["index", "morton_index"]
71    # Make some booleans
72    bo1 = sp1 & sp2
73    bo2 = sp1 - sp2
74    bo3 = sp1 | sp2
75    bo4 = ds.union([sp1, sp2])
76    bo5 = ds.intersection([sp1, sp2])
77    # Now make sure the indices also behave as we expect.
78    lens = np.intersect1d(i1, i2)
79    apple = np.setdiff1d(i1, i2)
80    both = np.union1d(i1, i2)
81    b1 = bo1["index", "morton_index"]
82    b1.sort()
83    b2 = bo2["index", "morton_index"]
84    b2.sort()
85    b3 = bo3["index", "morton_index"]
86    b3.sort()
87    assert_array_equal(b1, lens)
88    assert_array_equal(b2, apple)
89    assert_array_equal(b3, both)
90    b4 = bo4["index", "morton_index"]
91    b4.sort()
92    b5 = bo5["index", "morton_index"]
93    b5.sort()
94    assert_array_equal(b3, b4)
95    assert_array_equal(b1, b5)
96    bo6 = sp1 ^ sp2
97    b6 = bo6["index", "morton_index"]
98    b6.sort()
99    assert_array_equal(b6, np.setxor1d(i1, i2))
100
101
102def test_boolean_regions_no_overlap():
103    r"""Test to make sure that boolean objects (regions, no overlap)
104    behave the way we expect.
105
106    Test non-overlapping regions. This also checks that the original regions
107    don't change as part of constructing the booleans.
108    """
109    ds = fake_amr_ds()
110    re1 = ds.region([0.25] * 3, [0.2] * 3, [0.3] * 3)
111    re2 = ds.region([0.65] * 3, [0.6] * 3, [0.7] * 3)
112    # Store the original indices
113    i1 = re1["index", "morton_index"]
114    i1.sort()
115    i2 = re2["index", "morton_index"]
116    i2.sort()
117    ii = np.concatenate((i1, i2))
118    ii.sort()
119    # Make some booleans
120    bo1 = re1 & re2
121    bo2 = re1 - re2
122    bo3 = re1 | re2
123    bo4 = ds.union([re1, re2])
124    bo5 = ds.intersection([re1, re2])
125    # This makes sure the original containers didn't change.
126    new_i1 = re1["index", "morton_index"]
127    new_i1.sort()
128    new_i2 = re2["index", "morton_index"]
129    new_i2.sort()
130    assert_array_equal(new_i1, i1)
131    assert_array_equal(new_i2, i2)
132    # Now make sure the indices also behave as we expect.
133    empty = np.array([])
134    assert_array_equal(bo1["index", "morton_index"], empty)
135    assert_array_equal(bo5["index", "morton_index"], empty)
136    b2 = bo2["index", "morton_index"]
137    b2.sort()
138    assert_array_equal(b2, i1)
139    b3 = bo3["index", "morton_index"]
140    b3.sort()
141    assert_array_equal(b3, ii)
142    b4 = bo4["index", "morton_index"]
143    b4.sort()
144    b5 = bo5["index", "morton_index"]
145    b5.sort()
146    assert_array_equal(b3, b4)
147    bo6 = re1 ^ re2
148    b6 = bo6["index", "morton_index"]
149    b6.sort()
150    assert_array_equal(b6, np.setxor1d(i1, i2))
151
152
153def test_boolean_regions_overlap():
154    r"""Test to make sure that boolean objects (regions, overlap)
155    behave the way we expect.
156
157    Test overlapping regions.
158    """
159    ds = fake_amr_ds()
160    re1 = ds.region([0.55] * 3, [0.5] * 3, [0.6] * 3)
161    re2 = ds.region([0.6] * 3, [0.55] * 3, [0.65] * 3)
162    # Get indices of both.
163    i1 = re1["index", "morton_index"]
164    i2 = re2["index", "morton_index"]
165    # Make some booleans
166    bo1 = re1 & re2
167    bo2 = re1 - re2
168    bo3 = re1 | re2
169    bo4 = ds.union([re1, re2])
170    bo5 = ds.intersection([re1, re2])
171    # Now make sure the indices also behave as we expect.
172    cube = np.intersect1d(i1, i2)
173    bite_cube = np.setdiff1d(i1, i2)
174    both = np.union1d(i1, i2)
175    b1 = bo1["index", "morton_index"]
176    b1.sort()
177    b2 = bo2["index", "morton_index"]
178    b2.sort()
179    b3 = bo3["index", "morton_index"]
180    b3.sort()
181    assert_array_equal(b1, cube)
182    assert_array_equal(b2, bite_cube)
183    assert_array_equal(b3, both)
184    b4 = bo4["index", "morton_index"]
185    b4.sort()
186    b5 = bo5["index", "morton_index"]
187    b5.sort()
188    assert_array_equal(b3, b4)
189    assert_array_equal(b1, b5)
190    bo6 = re1 ^ re2
191    b6 = bo6["index", "morton_index"]
192    b6.sort()
193    assert_array_equal(b6, np.setxor1d(i1, i2))
194
195
196def test_boolean_cylinders_no_overlap():
197    r"""Test to make sure that boolean objects (cylinders, no overlap)
198    behave the way we expect.
199
200    Test non-overlapping cylinders. This also checks that the original cylinders
201    don't change as part of constructing the booleans.
202    """
203    ds = fake_amr_ds()
204    cyl1 = ds.disk([0.25] * 3, [1, 0, 0], 0.1, 0.1)
205    cyl2 = ds.disk([0.75] * 3, [1, 0, 0], 0.1, 0.1)
206    # Store the original indices
207    i1 = cyl1["index", "morton_index"]
208    i1.sort()
209    i2 = cyl2["index", "morton_index"]
210    i2.sort()
211    ii = np.concatenate((i1, i2))
212    ii.sort()
213    # Make some booleans
214    bo1 = cyl1 & cyl2
215    bo2 = cyl1 - cyl2
216    bo3 = cyl1 | cyl2
217    bo4 = ds.union([cyl1, cyl2])
218    bo5 = ds.intersection([cyl1, cyl2])
219    # This makes sure the original containers didn't change.
220    new_i1 = cyl1["index", "morton_index"]
221    new_i1.sort()
222    new_i2 = cyl2["index", "morton_index"]
223    new_i2.sort()
224    assert_array_equal(new_i1, i1)
225    assert_array_equal(new_i2, i2)
226    # Now make sure the indices also behave as we expect.
227    empty = np.array([])
228    assert_array_equal(bo1["index", "morton_index"], empty)
229    assert_array_equal(bo5["index", "morton_index"], empty)
230    b2 = bo2["index", "morton_index"]
231    b2.sort()
232    assert_array_equal(b2, i1)
233    b3 = bo3["index", "morton_index"]
234    b3.sort()
235    assert_array_equal(b3, ii)
236    b4 = bo4["index", "morton_index"]
237    b4.sort()
238    b5 = bo5["index", "morton_index"]
239    b5.sort()
240    assert_array_equal(b3, b4)
241    bo6 = cyl1 ^ cyl2
242    b6 = bo6["index", "morton_index"]
243    b6.sort()
244    assert_array_equal(b6, np.setxor1d(i1, i2))
245
246
247def test_boolean_cylinders_overlap():
248    r"""Test to make sure that boolean objects (cylinders, overlap)
249    behave the way we expect.
250
251    Test overlapping cylinders.
252    """
253    ds = fake_amr_ds()
254    cyl1 = ds.disk([0.45] * 3, [1, 0, 0], 0.2, 0.2)
255    cyl2 = ds.disk([0.55] * 3, [1, 0, 0], 0.2, 0.2)
256    # Get indices of both.
257    i1 = cyl1["index", "morton_index"]
258    i2 = cyl2["index", "morton_index"]
259    # Make some booleans
260    bo1 = cyl1 & cyl2
261    bo2 = cyl1 - cyl2
262    bo3 = cyl1 | cyl2
263    bo4 = ds.union([cyl1, cyl2])
264    bo5 = ds.intersection([cyl1, cyl2])
265    # Now make sure the indices also behave as we expect.
266    vlens = np.intersect1d(i1, i2)
267    bite_disk = np.setdiff1d(i1, i2)
268    both = np.union1d(i1, i2)
269    b1 = bo1["index", "morton_index"]
270    b1.sort()
271    b2 = bo2["index", "morton_index"]
272    b2.sort()
273    b3 = bo3["index", "morton_index"]
274    b3.sort()
275    assert_array_equal(b1, vlens)
276    assert_array_equal(b2, bite_disk)
277    assert_array_equal(b3, both)
278    b4 = bo4["index", "morton_index"]
279    b4.sort()
280    b5 = bo5["index", "morton_index"]
281    b5.sort()
282    assert_array_equal(b3, b4)
283    assert_array_equal(b1, b5)
284    bo6 = cyl1 ^ cyl2
285    b6 = bo6["index", "morton_index"]
286    b6.sort()
287    assert_array_equal(b6, np.setxor1d(i1, i2))
288    del ds
289
290
291def test_boolean_ellipsoids_no_overlap():
292    r"""Test to make sure that boolean objects (ellipsoids, no overlap)
293    behave the way we expect.
294
295    Test non-overlapping ellipsoids. This also checks that the original
296    ellipsoids don't change as part of constructing the booleans.
297    """
298    ds = fake_amr_ds()
299    ell1 = ds.ellipsoid([0.25] * 3, 0.05, 0.05, 0.05, np.array([0.1] * 3), 0.1)
300    ell2 = ds.ellipsoid([0.75] * 3, 0.05, 0.05, 0.05, np.array([0.1] * 3), 0.1)
301    # Store the original indices
302    i1 = ell1["index", "morton_index"]
303    i1.sort()
304    i2 = ell2["index", "morton_index"]
305    i2.sort()
306    ii = np.concatenate((i1, i2))
307    ii.sort()
308    # Make some booleans
309    bo1 = ell1 & ell2
310    bo2 = ell1 - ell2
311    bo3 = ell1 | ell2
312    bo4 = ds.union([ell1, ell2])
313    bo5 = ds.intersection([ell1, ell2])
314    # This makes sure the original containers didn't change.
315    new_i1 = ell1["index", "morton_index"]
316    new_i1.sort()
317    new_i2 = ell2["index", "morton_index"]
318    new_i2.sort()
319    assert_array_equal(new_i1, i1)
320    assert_array_equal(new_i2, i2)
321    # Now make sure the indices also behave as we expect.
322    empty = np.array([])
323    assert_array_equal(bo1["index", "morton_index"], empty)
324    assert_array_equal(bo5["index", "morton_index"], empty)
325    b2 = bo2["index", "morton_index"]
326    b2.sort()
327    assert_array_equal(b2, i1)
328    b3 = bo3["index", "morton_index"]
329    b3.sort()
330    assert_array_equal(b3, ii)
331    b4 = bo4["index", "morton_index"]
332    b4.sort()
333    b5 = bo5["index", "morton_index"]
334    b5.sort()
335    assert_array_equal(b3, b4)
336    bo6 = ell1 ^ ell2
337    b6 = bo6["index", "morton_index"]
338    b6.sort()
339    assert_array_equal(b6, np.setxor1d(i1, i2))
340
341
342def test_boolean_ellipsoids_overlap():
343    r"""Test to make sure that boolean objects (ellipsoids, overlap)
344    behave the way we expect.
345
346    Test overlapping ellipsoids.
347    """
348    ds = fake_amr_ds()
349    ell1 = ds.ellipsoid([0.45] * 3, 0.05, 0.05, 0.05, np.array([0.1] * 3), 0.1)
350    ell2 = ds.ellipsoid([0.55] * 3, 0.05, 0.05, 0.05, np.array([0.1] * 3), 0.1)
351    # Get indices of both.
352    i1 = ell1["index", "morton_index"]
353    i2 = ell2["index", "morton_index"]
354    # Make some booleans
355    bo1 = ell1 & ell2
356    bo2 = ell1 - ell2
357    bo3 = ell1 | ell2
358    bo4 = ds.union([ell1, ell2])
359    bo5 = ds.intersection([ell1, ell2])
360    # Now make sure the indices also behave as we expect.
361    overlap = np.intersect1d(i1, i2)
362    diff = np.setdiff1d(i1, i2)
363    both = np.union1d(i1, i2)
364    b1 = bo1["index", "morton_index"]
365    b1.sort()
366    b2 = bo2["index", "morton_index"]
367    b2.sort()
368    b3 = bo3["index", "morton_index"]
369    b3.sort()
370    assert_array_equal(b1, overlap)
371    assert_array_equal(b2, diff)
372    assert_array_equal(b3, both)
373    b4 = bo4["index", "morton_index"]
374    b4.sort()
375    b5 = bo5["index", "morton_index"]
376    b5.sort()
377    assert_array_equal(b3, b4)
378    assert_array_equal(b1, b5)
379    bo6 = ell1 ^ ell2
380    b6 = bo6["index", "morton_index"]
381    b6.sort()
382    assert_array_equal(b6, np.setxor1d(i1, i2))
383
384
385def test_boolean_mix_periodicity():
386    r"""Test that a hybrid boolean region behaves as we expect.
387
388    This also tests nested logic and that periodicity works.
389    """
390    ds = fake_amr_ds()
391    re = ds.region([0.5] * 3, [0.0] * 3, [1] * 3)  # whole thing
392    sp = ds.sphere([0.95] * 3, 0.3)  # wraps around
393    cyl = ds.disk([0.05] * 3, [1, 1, 1], 0.1, 0.4)  # wraps around
394    # Get original indices
395    rei = re["index", "morton_index"]
396    spi = sp["index", "morton_index"]
397    cyli = cyl["index", "morton_index"]
398    # Make some booleans
399    # whole box minux spherical bites at corners
400    bo1 = re - sp
401    # sphere plus cylinder
402    bo2 = sp | cyl
403    # a jumble, the region minus the sp+cyl
404    bo3 = re - (sp | cyl)
405    # Now make sure the indices also behave as we expect.
406    bo4 = ds.union([re, sp, cyl])
407    bo5 = ds.intersection([re, sp, cyl])
408    expect = np.setdiff1d(rei, spi)
409    ii = bo1["index", "morton_index"]
410    ii.sort()
411    assert_array_equal(expect, ii)
412    #
413    expect = np.union1d(spi, cyli)
414    ii = bo2["index", "morton_index"]
415    ii.sort()
416    assert_array_equal(expect, ii)
417    #
418    expect = np.union1d(spi, cyli)
419    expect = np.setdiff1d(rei, expect)
420    ii = bo3["index", "morton_index"]
421    ii.sort()
422    assert_array_equal(expect, ii)
423    b4 = bo4["index", "morton_index"]
424    b4.sort()
425    b5 = bo5["index", "morton_index"]
426    b5.sort()
427    ii = np.union1d(np.union1d(rei, cyli), spi)
428    ii.sort()
429    assert_array_equal(ii, b4)
430    ii = np.intersect1d(np.intersect1d(rei, cyli), spi)
431    ii.sort()
432    assert_array_equal(ii, b5)
433
434    bo6 = (re ^ sp) ^ cyl
435    b6 = bo6["index", "morton_index"]
436    b6.sort()
437    assert_array_equal(b6, np.setxor1d(np.setxor1d(rei, spi), cyli))
438
439
440def test_boolean_ray_region_no_overlap():
441    r"""Test to make sure that boolean objects (ray, region, no overlap)
442    behave the way we expect.
443
444    Test non-overlapping ray and region. This also checks that the original
445    objects don't change as part of constructing the booleans.
446    """
447    ds = fake_amr_ds()
448    re = ds.box([0.25] * 3, [0.75] * 3)
449    ra = ds.ray([0.1] * 3, [0.1, 0.1, 0.9])
450    # Store the original indices
451    i1 = re["index", "morton_index"]
452    i1.sort()
453    i2 = ra["index", "morton_index"]
454    i2.sort()
455    ii = np.concatenate((i1, i2))
456    ii.sort()
457    # Make some booleans
458    bo1 = re & ra
459    bo2 = re - ra
460    bo3 = re | ra
461    bo4 = ds.union([re, ra])
462    bo5 = ds.intersection([re, ra])
463    # This makes sure the original containers didn't change.
464    new_i1 = re["index", "morton_index"]
465    new_i1.sort()
466    new_i2 = ra["index", "morton_index"]
467    new_i2.sort()
468    assert_array_equal(new_i1, i1)
469    assert_array_equal(new_i2, i2)
470    # Now make sure the indices also behave as we expect.
471    empty = np.array([])
472    assert_array_equal(bo1["index", "morton_index"], empty)
473    assert_array_equal(bo5["index", "morton_index"], empty)
474    b2 = bo2["index", "morton_index"]
475    b2.sort()
476    assert_array_equal(b2, i1)
477    b3 = bo3["index", "morton_index"]
478    b3.sort()
479    assert_array_equal(b3, ii)
480    b4 = bo4["index", "morton_index"]
481    b4.sort()
482    b5 = bo5["index", "morton_index"]
483    b5.sort()
484    assert_array_equal(b3, b4)
485    bo6 = re ^ ra
486    b6 = bo6["index", "morton_index"]
487    b6.sort()
488    assert_array_equal(b6, np.setxor1d(i1, i2))
489
490
491def test_boolean_ray_region_overlap():
492    r"""Test to make sure that boolean objects (ray, region, overlap)
493    behave the way we expect.
494
495    Test overlapping ray and region. This also checks that the original
496    objects don't change as part of constructing the booleans.
497    """
498    ds = fake_amr_ds()
499    re = ds.box([0.25] * 3, [0.75] * 3)
500    ra = ds.ray([0] * 3, [1] * 3)
501    # Get indices of both.
502    i1 = re["index", "morton_index"]
503    i2 = ra["index", "morton_index"]
504    # Make some booleans
505    bo1 = re & ra
506    bo2 = re - ra
507    bo3 = re | ra
508    bo4 = ds.union([re, ra])
509    bo5 = ds.intersection([re, ra])
510    # Now make sure the indices also behave as we expect.
511    short_line = np.intersect1d(i1, i2)
512    cube_minus_line = np.setdiff1d(i1, i2)
513    both = np.union1d(i1, i2)
514    b1 = bo1["index", "morton_index"]
515    b1.sort()
516    b2 = bo2["index", "morton_index"]
517    b2.sort()
518    b3 = bo3["index", "morton_index"]
519    b3.sort()
520    assert_array_equal(b1, short_line)
521    assert_array_equal(b2, cube_minus_line)
522    assert_array_equal(b3, both)
523    b4 = bo4["index", "morton_index"]
524    b4.sort()
525    b5 = bo5["index", "morton_index"]
526    b5.sort()
527    assert_array_equal(b3, b4)
528    assert_array_equal(b1, b5)
529    bo6 = re ^ ra
530    b6 = bo6["index", "morton_index"]
531    b6.sort()
532    assert_array_equal(b6, np.setxor1d(i1, i2))
533
534
535def test_boolean_rays_no_overlap():
536    r"""Test to make sure that boolean objects (rays, no overlap)
537    behave the way we expect.
538
539    Test non-overlapping rays.
540    """
541    ds = fake_amr_ds()
542    ra1 = ds.ray([0, 0, 0], [0, 0, 1])
543    ra2 = ds.ray([1, 0, 0], [1, 0, 1])
544    # Store the original indices
545    i1 = ra1["index", "morton_index"]
546    i1.sort()
547    i2 = ra2["index", "morton_index"]
548    i2.sort()
549    ii = np.concatenate((i1, i2))
550    ii.sort()
551    # Make some booleans
552    bo1 = ra1 & ra2
553    bo2 = ra1 - ra2
554    bo3 = ra1 | ra2
555    bo4 = ds.union([ra1, ra2])
556    bo5 = ds.intersection([ra1, ra2])
557    # This makes sure the original containers didn't change.
558    new_i1 = ra1["index", "morton_index"]
559    new_i1.sort()
560    new_i2 = ra2["index", "morton_index"]
561    new_i2.sort()
562    assert_array_equal(new_i1, i1)
563    assert_array_equal(new_i2, i2)
564    # Now make sure the indices also behave as we expect.
565    empty = np.array([])
566    assert_array_equal(bo1["index", "morton_index"], empty)
567    assert_array_equal(bo5["index", "morton_index"], empty)
568    b2 = bo2["index", "morton_index"]
569    b2.sort()
570    assert_array_equal(b2, i1)
571    b3 = bo3["index", "morton_index"]
572    b3.sort()
573    assert_array_equal(b3, ii)
574    b4 = bo4["index", "morton_index"]
575    b4.sort()
576    b5 = bo5["index", "morton_index"]
577    b5.sort()
578    assert_array_equal(b3, b4)
579    bo6 = ra1 ^ ra2
580    b6 = bo6["index", "morton_index"]
581    b6.sort()
582    assert_array_equal(b6, np.setxor1d(i1, i2))
583
584
585def test_boolean_rays_overlap():
586    r"""Test to make sure that boolean objects (rays, overlap)
587    behave the way we expect.
588
589    Test non-overlapping rays.
590    """
591    ds = fake_amr_ds()
592    ra1 = ds.ray([0] * 3, [1] * 3)
593    ra2 = ds.ray([0] * 3, [0.5] * 3)
594    # Get indices of both.
595    i1 = ra1["index", "morton_index"]
596    i1.sort()
597    i2 = ra2["index", "morton_index"]
598    i2.sort()
599    ii = np.concatenate((i1, i2))
600    ii.sort()
601    # Make some booleans
602    bo1 = ra1 & ra2
603    bo2 = ra1 - ra2
604    bo3 = ra1 | ra2
605    bo4 = ds.union([ra1, ra2])
606    bo5 = ds.intersection([ra1, ra2])
607    # Now make sure the indices also behave as we expect.
608    short_line = np.intersect1d(i1, i2)
609    short_line_b = np.setdiff1d(i1, i2)
610    full_line = np.union1d(i1, i2)
611    b1 = bo1["index", "morton_index"]
612    b1.sort()
613    b2 = bo2["index", "morton_index"]
614    b2.sort()
615    b3 = bo3["index", "morton_index"]
616    b3.sort()
617    assert_array_equal(b1, short_line)
618    assert_array_equal(b2, short_line_b)
619    assert_array_equal(b3, full_line)
620    b4 = bo4["index", "morton_index"]
621    b4.sort()
622    b5 = bo5["index", "morton_index"]
623    b5.sort()
624    assert_array_equal(b3, i1)
625    assert_array_equal(b3, b4)
626    assert_array_equal(b1, b5)
627    bo6 = ra1 ^ ra2
628    b6 = bo6["index", "morton_index"]
629    b6.sort()
630    assert_array_equal(b6, np.setxor1d(i1, i2))
631
632
633def test_boolean_slices_no_overlap():
634    r"""Test to make sure that boolean objects (slices, no overlap)
635    behave the way we expect.
636
637    Test non-overlapping slices. This also checks that the original regions
638    don't change as part of constructing the booleans.
639    """
640    ds = fake_amr_ds()
641    sl1 = ds.r[:, :, 0.25]
642    sl2 = ds.r[:, :, 0.75]
643    # Store the original indices
644    i1 = sl1["index", "morton_index"]
645    i1.sort()
646    i2 = sl2["index", "morton_index"]
647    i2.sort()
648    ii = np.concatenate((i1, i2))
649    ii.sort()
650    # Make some booleans
651    bo1 = sl1 & sl2
652    bo2 = sl1 - sl2
653    bo3 = sl1 | sl2
654    bo4 = ds.union([sl1, sl2])
655    bo5 = ds.intersection([sl1, sl2])
656    # This makes sure the original containers didn't change.
657    new_i1 = sl1["index", "morton_index"]
658    new_i1.sort()
659    new_i2 = sl2["index", "morton_index"]
660    new_i2.sort()
661    assert_array_equal(new_i1, i1)
662    assert_array_equal(new_i2, i2)
663    # Now make sure the indices also behave as we expect.
664    empty = np.array([])
665    assert_array_equal(bo1["index", "morton_index"], empty)
666    assert_array_equal(bo5["index", "morton_index"], empty)
667    b2 = bo2["index", "morton_index"]
668    b2.sort()
669    assert_array_equal(b2, i1)
670    b3 = bo3["index", "morton_index"]
671    b3.sort()
672    assert_array_equal(b3, ii)
673    b4 = bo4["index", "morton_index"]
674    b4.sort()
675    b5 = bo5["index", "morton_index"]
676    b5.sort()
677    assert_array_equal(b3, b4)
678    bo6 = sl1 ^ sl2
679    b6 = bo6["index", "morton_index"]
680    b6.sort()
681    assert_array_equal(b6, np.setxor1d(i1, i2))
682
683
684def test_boolean_slices_overlap():
685    r"""Test to make sure that boolean objects (slices, overlap)
686    behave the way we expect.
687
688    Test overlapping slices.
689    """
690    ds = fake_amr_ds()
691    sl1 = ds.r[:, :, 0.25]
692    sl2 = ds.r[:, 0.75, :]
693    # Get indices of both.
694    i1 = sl1["index", "morton_index"]
695    i2 = sl2["index", "morton_index"]
696    # Make some booleans
697    bo1 = sl1 & sl2
698    bo2 = sl1 - sl2
699    bo3 = sl1 | sl2
700    bo4 = ds.union([sl1, sl2])
701    bo5 = ds.intersection([sl1, sl2])
702    # Now make sure the indices also behave as we expect.
703    line = np.intersect1d(i1, i2)
704    orig = np.setdiff1d(i1, i2)
705    both = np.union1d(i1, i2)
706    b1 = bo1["index", "morton_index"]
707    b1.sort()
708    b2 = bo2["index", "morton_index"]
709    b2.sort()
710    b3 = bo3["index", "morton_index"]
711    b3.sort()
712    assert_array_equal(b1, line)
713    assert_array_equal(b2, orig)
714    assert_array_equal(b3, both)
715    b4 = bo4["index", "morton_index"]
716    b4.sort()
717    b5 = bo5["index", "morton_index"]
718    b5.sort()
719    assert_array_equal(b3, b4)
720    assert_array_equal(b1, b5)
721    bo6 = sl1 ^ sl2
722    b6 = bo6["index", "morton_index"]
723    b6.sort()
724    assert_array_equal(b6, np.setxor1d(i1, i2))
725
726
727def test_boolean_ray_slice_no_overlap():
728    r"""Test to make sure that boolean objects (ray, slice, no overlap)
729    behave the way we expect.
730
731    Test non-overlapping ray and slice. This also checks that the original
732    regions don't change as part of constructing the booleans.
733    """
734    ds = fake_amr_ds()
735    sl = ds.r[:, :, 0.25]
736    ra = ds.ray([0] * 3, [0, 1, 0])
737    # Store the original indices
738    i1 = sl["index", "morton_index"]
739    i1.sort()
740    i2 = ra["index", "morton_index"]
741    i2.sort()
742    ii = np.concatenate((i1, i2))
743    ii.sort()
744    # Make some booleans
745    bo1 = sl & ra
746    bo2 = sl - ra
747    bo3 = sl | ra
748    bo4 = ds.union([sl, ra])
749    bo5 = ds.intersection([sl, ra])
750    # This makes sure the original containers didn't change.
751    new_i1 = sl["index", "morton_index"]
752    new_i1.sort()
753    new_i2 = ra["index", "morton_index"]
754    new_i2.sort()
755    assert_array_equal(new_i1, i1)
756    assert_array_equal(new_i2, i2)
757    # Now make sure the indices also behave as we expect.
758    empty = np.array([])
759    assert_array_equal(bo1["index", "morton_index"], empty)
760    assert_array_equal(bo5["index", "morton_index"], empty)
761    b2 = bo2["index", "morton_index"]
762    b2.sort()
763    assert_array_equal(b2, i1)
764    b3 = bo3["index", "morton_index"]
765    b3.sort()
766    assert_array_equal(b3, ii)
767    b4 = bo4["index", "morton_index"]
768    b4.sort()
769    b5 = bo5["index", "morton_index"]
770    b5.sort()
771    assert_array_equal(b3, b4)
772    bo6 = sl ^ ra
773    b6 = bo6["index", "morton_index"]
774    b6.sort()
775    assert_array_equal(b6, np.setxor1d(i1, i2))
776
777
778def test_boolean_ray_slice_overlap():
779    r"""Test to make sure that boolean objects (rays and slices, overlap)
780    behave the way we expect.
781
782    Test overlapping rays and slices.
783    """
784    ds = fake_amr_ds()
785    sl = ds.r[:, :, 0.25]
786    ra = ds.ray([0, 0, 0.25], [0, 1, 0.25])
787    # Get indices of both.
788    i1 = sl["index", "morton_index"]
789    i1.sort()
790    i2 = ra["index", "morton_index"]
791    i1.sort()
792    ii = np.concatenate((i1, i2))
793    ii.sort()
794    # Make some booleans
795    bo1 = sl & ra
796    bo2 = sl - ra
797    bo3 = sl | ra
798    bo4 = ds.union([sl, ra])
799    bo5 = ds.intersection([sl, ra])
800    # Now make sure the indices also behave as we expect.
801    line = np.intersect1d(i1, i2)
802    sheet_minus_line = np.setdiff1d(i1, i2)
803    sheet = np.union1d(i1, i2)
804    b1 = bo1["index", "morton_index"]
805    b1.sort()
806    b2 = bo2["index", "morton_index"]
807    b2.sort()
808    b3 = bo3["index", "morton_index"]
809    b3.sort()
810    assert_array_equal(b1, line)
811    assert_array_equal(b2, sheet_minus_line)
812    assert_array_equal(b3, sheet)
813    b4 = bo4["index", "morton_index"]
814    b4.sort()
815    b5 = bo5["index", "morton_index"]
816    b5.sort()
817    assert_array_equal(b3, i1)
818    assert_array_equal(b3, b4)
819    assert_array_equal(b1, b5)
820    bo6 = sl ^ ra
821    b6 = bo6["index", "morton_index"]
822    b6.sort()
823    assert_array_equal(b6, np.setxor1d(i1, i2))
824