@@ -650,307 +650,6 @@ def _compare_ad_objects(a, b):
650650 )
651651
652652
653- @pytest .mark .parametrize ("prev_time" , [True , False ])
654- def test_ad_variable_prev_time_and_iter (prev_time ):
655- # Test only 1 variable, the rest should be covered by other tests
656- mdg , _ = pp .mdg_library .square_with_orthogonal_fractures (
657- "cartesian" ,
658- {"cell_size" : 0.5 },
659- fracture_indices = [1 ],
660- )
661- equation_system = pp .ad .EquationSystem (mdg )
662-
663- # Integer to test the depth of prev _*, could be a test parameter, but no need
664- depth = 4
665- var_name = "foo"
666- vec = np .ones (mdg .num_subdomain_cells ())
667-
668- equation_system .create_variables (
669- var_name , dof_info = {"cells" : 1 }, subdomains = mdg .subdomains ()
670- )
671- var = equation_system .md_variable (var_name )
672-
673- # Starting point is time step index is None, iterate index is 0
674- # (current time and iter)
675- assert var .time_step_index is None
676- assert var .iterate_index == 0
677-
678- # For AD to work, we need at least values at iterate_index = 0
679- equation_system .set_variable_values (vec * 0.0 , [var ], iterate_index = 0 )
680-
681- # Test configuration dependent on whether prev iter or prev time is tested.
682- # Code is analogous
683- if prev_time :
684- index_key = "time_step_index"
685- other_index_key = "iterate_index"
686- get_prev_key = "previous_timestep"
687-
688- # prohibit prev time step variable to also be prev iter
689- with pytest .raises (ValueError ):
690- var_pt = var .previous_timestep ()
691- _ = var_pt .previous_iteration ()
692- else :
693- index_key = "iterate_index"
694- other_index_key = "time_step_index"
695- get_prev_key = "previous_iteration"
696-
697- # prohibit prev iter variable to also be prev time
698- with pytest .raises (ValueError ):
699- var_pi = var .previous_iteration ()
700- _ = var_pi .previous_timestep ()
701-
702- # Set values except for the last step. The current value is set above
703- for i in range (depth - 1 ):
704- equation_system .set_variable_values (vec * i , [var ], ** {index_key : i })
705-
706- # Evaluating the last step, should raise a key error because no values set
707- with pytest .raises (KeyError ):
708- var_prev = getattr (var , get_prev_key )(steps = depth )
709- _ = equation_system .evaluate (var_prev )
710-
711- # Evaluate prev var and check that the values are what they're supposed to be. First
712- # check current variable value.
713- var = getattr (var , get_prev_key )(steps = 0 )
714- val_0 = equation_system .evaluate (var )
715- assert np .allclose (val_0 , 0 )
716- # Then do the same for all previous steps.
717- for i in range (depth - 1 ):
718- var_i = getattr (var , get_prev_key )(steps = i + 1 )
719- val_i = equation_system .evaluate (var_i )
720- assert np .allclose (val_i , i )
721- if i > 0 :
722- # prev var has no Jacobian. That is not the case for i=0, corresponding to
723- # the variable itself.
724- ad_i = var_i .value_and_jacobian (equation_system )
725- assert np .all (ad_i .jac .toarray () == 0.0 )
726-
727- # Test creating with explicit stepping and recursive stepping
728- vars_exp = [getattr (var , get_prev_key )(steps = i ) for i in range (0 , depth )]
729-
730- vars_rec = []
731- for i in range (0 , depth ):
732- var_i = copy .copy (var )
733- for _ in range (i ):
734- var_i = getattr (var_i , get_prev_key )()
735- vars_rec .append (var_i )
736-
737- assert len (vars_exp ) == len (vars_rec )
738- vals_exp = [equation_system .evaluate (v ) for v in vars_exp ]
739- vals_rec = [equation_system .evaluate (v ) for v in vars_rec ]
740-
741- for v_e , v_r in zip (vals_exp , vals_rec ):
742- assert np .allclose (v_e , v_r )
743-
744- # Testing IDs. NOTE as of now, variables at prev iter have the same ID until
745- # full support is given
746- all_ids = set ([var .id ] + [v .id for v in vars_exp ] + [v .id for v in vars_rec ])
747- assert len (all_ids ) == 1
748-
749- # Testing index values.
750- # For prev time, time step index increases starting from 0, while iterate is None
751- # For prev iter, iterate index increases starting from 0, while time is always None
752- # Only relevant for previous values, not the variable itself.
753- for i in range (depth - 1 ):
754- assert getattr (vars_exp [i + 1 ], index_key ) == i
755- assert getattr (vars_exp [i + 1 ], other_index_key ) is None
756- assert getattr (vars_rec [i + 1 ], index_key ) == i
757- assert getattr (vars_rec [i + 1 ], other_index_key ) is None
758-
759-
760- @pytest .mark .parametrize ("reference" , [None , "set" , "shift" ])
761- @pytest .mark .parametrize ("state" , [None , "previous_timestep" , "previous_iteration" ])
762- def test_ad_variable_reference (reference , state ):
763- """Test the reference values of variables.
764-
765- Test whether explicitly set and default reference values are correctly evaluated,
766- and that the associated Jacobian of the reference is zero.
767-
768- Test both for the current variable, and for variables at previous time steps and
769- iterations.
770-
771- """
772- mdg , _ = pp .mdg_library .square_with_orthogonal_fractures (
773- "cartesian" ,
774- {"cell_size" : 0.5 },
775- fracture_indices = [1 ],
776- )
777- equation_system = pp .ad .EquationSystem (mdg )
778-
779- # Integer to test the depth of prev _*, could be a test parameter, but no need
780- var_name = "foo"
781- vec = np .ones (mdg .num_subdomain_cells ())
782-
783- equation_system .create_variables (
784- var_name , dof_info = {"cells" : 1 }, subdomains = mdg .subdomains ()
785- )
786- var = equation_system .md_variable (var_name )
787-
788- # Starting point is that the variable is not a reference.
789- assert var .is_reference is False
790-
791- # For AD to work, we need at least values at iterate_index = 0.
792- # Set purposefully different values than for reference.
793- equation_system .set_variable_values (vec * 3.0 , [var ], iterate_index = 0 )
794- equation_system .set_variable_values (vec * 2.0 , [var ], time_step_index = 0 )
795-
796- # Define reference values, depending on the test parameter.
797- if reference is None :
798- # No action, the reference values should be the default (empty/zero).
799- pass
800- elif reference == "set" :
801- # Explicitly set the reference values.
802- equation_system .set_variable_values (vec * 1.0 , [var ], reference = True )
803- elif reference == "shift" :
804- # Shift current approximation to reference values.
805- for _ , data in mdg .subdomains (return_data = True ):
806- pp .shift_solution_values (var .name , data , pp .REFERENCE_SOLUTIONS )
807-
808- # Bring variable in correct state for testing.
809- if state is None :
810- # No action, variable is already in correct state.
811- pass
812- elif state == "previous_timestep" :
813- var = var .previous_timestep ()
814- elif state == "previous_iteration" :
815- var = var .previous_iteration ()
816-
817- # Value of variable.
818- ad_var = var .value_and_jacobian (equation_system )
819-
820- # Evaluate reference and check that the values are what they're supposed to be.
821- ref = var .reference ()
822- # Only expect reference for current iteration.
823- assert ref .is_reference == (state == None )
824- # Expected value.
825- if reference is None :
826- expected_ref_val = 0.0 if ref .is_reference else ad_var .val
827- elif reference == "set" :
828- expected_ref_val = 1.0 if ref .is_reference else ad_var .val
829- elif reference == "shift" :
830- expected_ref_val = 3.0 if ref .is_reference else ad_var .val
831-
832- val_ref = equation_system .evaluate (ref )
833- ad_ref = ref .value_and_jacobian (equation_system )
834- assert np .allclose (val_ref , expected_ref_val )
835- assert np .allclose (ad_ref .val , expected_ref_val )
836- assert np .all (ad_ref .jac .toarray () == 0.0 )
837-
838- # Evaluate perturbation to reference and check that the values are what they're
839- # supposed to be.
840- perturbation = var .perturbation_from_reference ()
841- val_perturbation = equation_system .evaluate (perturbation )
842- ad_perturbation = perturbation .value_and_jacobian (equation_system )
843- assert np .allclose (val_perturbation , ad_var .val - expected_ref_val )
844- assert np .allclose (ad_perturbation .val , ad_var .val - expected_ref_val )
845- assert np .all (ad_perturbation .jac .toarray () == ad_var .jac .toarray ())
846-
847- # Combine reference and perturbation, should give the same value as the
848- # variable itself.
849- combined = ref + perturbation
850- val_combined = equation_system .evaluate (combined )
851- assert np .allclose (val_combined , ad_var .val )
852- ad_combined = combined .value_and_jacobian (equation_system )
853- assert np .allclose (ad_combined .val , ad_var .val )
854- assert np .allclose (ad_combined .jac .toarray (), ad_var .jac .toarray ())
855-
856- # Check time increments of reference is zero.
857- if state is None :
858- ref_increment = pp .ad .time_increment (ref )
859- val_ref_increment = equation_system .evaluate (ref_increment )
860- assert np .allclose (val_ref_increment , 0.0 )
861-
862-
863- @pytest .mark .parametrize ("state" , [None , "previous_timestep" ])
864- @pytest .mark .parametrize ("reference" , [None , "set" , "shift" ])
865- def test_time_dependent_array_reference (state , reference ):
866- # Time-dependent arrays are defined on grids.
867- # Some boilerplate is needed to define these.
868- mdg , _ = pp .mdg_library .square_with_orthogonal_fractures (
869- "cartesian" ,
870- {"cell_size" : 0.2 },
871- fracture_indices = [1 ],
872- )
873- for sd , sd_data in mdg .subdomains (return_data = True ):
874- vals_sol = np .zeros (sd .num_cells )
875- pp .set_solution_values (
876- name = "foo" , values = vals_sol , data = sd_data , time_step_index = 0
877- )
878- vals_it = 2 * np .ones (sd .num_cells )
879- pp .set_solution_values (
880- name = "foo" , values = vals_it , data = sd_data , iterate_index = 0
881- )
882-
883- if reference is None :
884- # No action, the reference values should be the default (empty/zero).
885- pass
886- elif reference == "set" :
887- # Explicitly set the reference values.
888- vals_ref = np .ones (sd .num_cells )
889- pp .set_solution_values (
890- name = "foo" , values = vals_ref , data = sd_data , reference = True
891- )
892- elif reference == "shift" :
893- # Shift current approximation to reference values.
894- pp .shift_solution_values (
895- name = "foo" , data = sd_data , location = pp .REFERENCE_SOLUTIONS
896- )
897-
898- # We make three arrays: One defined on a single subdomain, one on all subdomains of
899- # mdg and one on an interface.
900- sd_array = pp .ad .TimeDependentDenseArray (
901- "foo" , domains = mdg .subdomains (dim = mdg .dim_max ())
902- )
903-
904- # Bring array in correct state for testing.
905- # Value of variable.
906- if state is None :
907- # No action, variable is already in correct state.
908- assert np .allclose (sd_array .parse (mdg ), 2 )
909- elif state == "previous_timestep" :
910- sd_array = sd_array .previous_timestep ()
911- assert np .allclose (sd_array .parse (mdg ), 0 )
912-
913- # Build reference and check status.
914- ref = sd_array .reference ()
915- # Only expect reference for current iteration.
916- if isinstance (ref , pp .numerics .ad ._derived_operators .ReferenceOperator ):
917- assert ref .is_reference == (state == None )
918-
919- # Expected value.
920- array_val = sd_array .parse (mdg )
921- if reference is None :
922- expected_ref_val = 0.0 if ref .is_reference else array_val
923- elif reference == "set" :
924- expected_ref_val = 1.0 if ref .is_reference else array_val
925- elif reference == "shift" :
926- expected_ref_val = 2.0 if ref .is_reference else array_val
927-
928- # Evaluate reference and check that the values are what they're supposed to be.
929- val_ref = ref .parse (mdg )
930- assert np .allclose (val_ref , expected_ref_val )
931-
932- # Evaluate and check perturbation to reference.
933- # Require equation system for evaluation - parsing not sufficient.
934- equation_system = pp .ad .EquationSystem (mdg )
935- var_name = "foo_var"
936- equation_system .create_variables (
937- var_name , dof_info = {"cells" : 1 }, subdomains = mdg .subdomains ()
938- )
939- var = equation_system .md_variable (var_name )
940- vec = np .ones (mdg .num_subdomain_cells ())
941- equation_system .set_variable_values (vec * 3.0 , [var ], iterate_index = 0 )
942- equation_system .set_variable_values (vec * 2.0 , [var ], time_step_index = 0 )
943- perturbation = sd_array .perturbation_from_reference ()
944- val_perturbation = equation_system .evaluate (perturbation )
945- assert np .allclose (val_perturbation , array_val - expected_ref_val )
946-
947- # Check time increments of reference is zero.
948- if state is None :
949- ref_increment = pp .ad .time_increment (ref )
950- val_ref_increment = equation_system .evaluate (ref_increment )
951- assert np .allclose (val_ref_increment , 0.0 )
952-
953-
954653@pytest .mark .parametrize (
955654 "grids" ,
956655 [
0 commit comments