@@ -296,22 +296,183 @@ def test_laplacian(f):
296296 laplacian (output_ = output_ , input_ = input_ , components = ["a" , "b" , "c" ])
297297
298298
299- def test_advection ():
299+ def test_advection_scalar ():
300300
301- # Define input and output
301+ # Define 3-dimensional input
302302 input_ = torch .rand ((20 , 3 ), requires_grad = True )
303303 input_ = LabelTensor (input_ , ["x" , "y" , "z" ])
304- output_ = LabelTensor (input_ ** 2 , ["u" , "v" , "c" ])
305304
306- # Define the velocity field
307- velocity = output_ .extract (["c" ])
305+ # Define 3-dimensional velocity field and quantity to be advected
306+ velocity = torch .rand ((20 , 3 ), requires_grad = True )
307+ field = torch .sum (input_ ** 2 , dim = - 1 , keepdim = True )
308+
309+ # Combine velocity and field into a LabelTensor
310+ labels = ["ux" , "uy" , "uz" , "c" ]
311+ output_ = LabelTensor (torch .cat ((velocity , field ), dim = 1 ), labels )
312+
313+ # Compute the pina advection
314+ components = ["c" ]
315+ pina_adv = advection (
316+ output_ = output_ ,
317+ input_ = input_ ,
318+ velocity_field = ["ux" , "uy" , "uz" ],
319+ components = components ,
320+ d = ["x" , "y" , "z" ],
321+ )
322+
323+ # Compute the true advection
324+ grads = 2 * input_
325+ true_adv = torch .sum (grads * velocity , dim = grads .ndim - 1 , keepdim = True )
326+
327+ # Check the shape, labels, and value of the advection
328+ assert pina_adv .shape == (* output_ .shape [:- 1 ], len (components ))
329+ assert pina_adv .labels == ["adv_c" ]
330+ assert torch .allclose (pina_adv , true_adv )
331+
332+ # Should fail if input not a LabelTensor
333+ with pytest .raises (TypeError ):
334+ advection (
335+ output_ = output_ ,
336+ input_ = input_ .tensor ,
337+ velocity_field = ["ux" , "uy" , "uz" ],
338+ )
339+
340+ # Should fail if output not a LabelTensor
341+ with pytest .raises (TypeError ):
342+ advection (
343+ output_ = output_ .tensor ,
344+ input_ = input_ ,
345+ velocity_field = ["ux" , "uy" , "uz" ],
346+ )
347+
348+ # Should fail for non-existent input labels
349+ with pytest .raises (RuntimeError ):
350+ advection (
351+ output_ = output_ ,
352+ input_ = input_ ,
353+ d = ["x" , "a" ],
354+ velocity_field = ["ux" , "uy" , "uz" ],
355+ )
356+
357+ # Should fail for non-existent output labels
358+ with pytest .raises (RuntimeError ):
359+ advection (
360+ output_ = output_ ,
361+ input_ = input_ ,
362+ components = ["a" , "b" , "c" ],
363+ velocity_field = ["ux" , "uy" , "uz" ],
364+ )
365+
366+ # Should fail if velocity_field labels are not present in the output labels
367+ with pytest .raises (RuntimeError ):
368+ advection (
369+ output_ = output_ ,
370+ input_ = input_ ,
371+ velocity_field = ["ux" , "uy" , "nonexistent" ],
372+ components = ["c" ],
373+ )
374+
375+ # Should fail if velocity_field dimensionality does not match input tensor
376+ with pytest .raises (RuntimeError ):
377+ advection (
378+ output_ = output_ ,
379+ input_ = input_ ,
380+ velocity_field = ["ux" , "uy" ],
381+ components = ["c" ],
382+ )
383+
384+
385+ def test_advection_vector ():
308386
309- # Compute the true advection and the pina advection
310- pina_advection = advection (
311- output_ = output_ , input_ = input_ , velocity_field = "c"
387+ # Define 3-dimensional input
388+ input_ = torch .rand ((20 , 3 ), requires_grad = True )
389+ input_ = LabelTensor (input_ , ["x" , "y" , "z" ])
390+
391+ # Define 3-dimensional velocity field
392+ velocity = torch .rand ((20 , 3 ), requires_grad = True )
393+
394+ # Define 2-dimensional field to be advected
395+ field_1 = torch .sum (input_ ** 2 , dim = - 1 , keepdim = True )
396+ field_2 = torch .sum (input_ ** 3 , dim = - 1 , keepdim = True )
397+
398+ # Combine velocity and field into a LabelTensor
399+ labels = ["ux" , "uy" , "uz" , "c1" , "c2" ]
400+ output_ = LabelTensor (
401+ torch .cat ((velocity , field_1 , field_2 ), dim = 1 ), labels
402+ )
403+
404+ # Compute the pina advection
405+ components = ["c1" , "c2" ]
406+ pina_adv = advection (
407+ output_ = output_ ,
408+ input_ = input_ ,
409+ velocity_field = ["ux" , "uy" , "uz" ],
410+ components = components ,
411+ d = ["x" , "y" , "z" ],
312412 )
313- true_advection = velocity * 2 * input_ .extract (["x" , "y" ])
314413
315- # Check the shape of the advection
316- assert pina_advection .shape == (* output_ .shape [:- 1 ], output_ .shape [- 1 ] - 1 )
317- assert torch .allclose (pina_advection , true_advection )
414+ # Compute the true gradients of the fields "c1", "c2"
415+ grads1 = 2 * input_
416+ grads2 = 3 * input_ ** 2
417+
418+ # Compute the true advection for each field
419+ true_adv1 = torch .sum (grads1 * velocity , dim = grads1 .ndim - 1 , keepdim = True )
420+ true_adv2 = torch .sum (grads2 * velocity , dim = grads2 .ndim - 1 , keepdim = True )
421+ true_adv = torch .cat ((true_adv1 , true_adv2 ), dim = - 1 )
422+
423+ # Check the shape, labels, and value of the advection
424+ assert pina_adv .shape == (* output_ .shape [:- 1 ], len (components ))
425+ assert pina_adv .labels == ["adv_c1" , "adv_c2" ]
426+ assert torch .allclose (pina_adv , true_adv )
427+
428+ # Should fail if input not a LabelTensor
429+ with pytest .raises (TypeError ):
430+ advection (
431+ output_ = output_ ,
432+ input_ = input_ .tensor ,
433+ velocity_field = ["ux" , "uy" , "uz" ],
434+ )
435+
436+ # Should fail if output not a LabelTensor
437+ with pytest .raises (TypeError ):
438+ advection (
439+ output_ = output_ .tensor ,
440+ input_ = input_ ,
441+ velocity_field = ["ux" , "uy" , "uz" ],
442+ )
443+
444+ # Should fail for non-existent input labels
445+ with pytest .raises (RuntimeError ):
446+ advection (
447+ output_ = output_ ,
448+ input_ = input_ ,
449+ d = ["x" , "a" ],
450+ velocity_field = ["ux" , "uy" , "uz" ],
451+ )
452+
453+ # Should fail for non-existent output labels
454+ with pytest .raises (RuntimeError ):
455+ advection (
456+ output_ = output_ ,
457+ input_ = input_ ,
458+ components = ["a" , "b" , "c" ],
459+ velocity_field = ["ux" , "uy" , "uz" ],
460+ )
461+
462+ # Should fail if velocity_field labels are not present in the output labels
463+ with pytest .raises (RuntimeError ):
464+ advection (
465+ output_ = output_ ,
466+ input_ = input_ ,
467+ velocity_field = ["ux" , "uy" , "nonexistent" ],
468+ components = ["c" ],
469+ )
470+
471+ # Should fail if velocity_field dimensionality does not match input tensor
472+ with pytest .raises (RuntimeError ):
473+ advection (
474+ output_ = output_ ,
475+ input_ = input_ ,
476+ velocity_field = ["ux" , "uy" ],
477+ components = ["c" ],
478+ )
0 commit comments