def sanity_check(cls, scenario_dict, check_self_type=False, valid_check=False):
        """Check if the input scenario dict is self-consistent and has filled required fields.

        The required high-level fields include tracks, dynamic_map_states, metadata, map_features.
        For each object, the tracks[obj_id] should at least contain type, state, metadata.
        For each object, the tracks[obj_id]['state'] should at least contain position, heading.
        For each lane in map_features, map_feature[map_feat_id] should at least contain polyline.
        For metadata, it should at least contain metadrive_processed, coordinate and timestep.
        We have more checks to ensure the consistency of the data.

        Args:
            scenario_dict: the input dict.
            check_self_type: if True, assert the input dict is a native Python dict.
            valid_check: if True, we will assert the values for a given timestep are zeros if valid=False at that
                timestep.
        """
        if check_self_type:
            assert isinstance(scenario_dict, dict)
            assert not isinstance(scenario_dict, ScenarioDescription)

        # Whether input has all required keys
        assert cls.FIRST_LEVEL_KEYS.issubset(set(scenario_dict.keys())), \
            "You lack these keys in first level: {}".format(cls.FIRST_LEVEL_KEYS.difference(set(scenario_dict.keys())))

        # Check types, only native python objects
        # This is to avoid issue in pickle deserialization
        _recursive_check_type(scenario_dict, cls.ALLOW_TYPES)

        scenario_length = scenario_dict[cls.LENGTH]

        # Check tracks data
        assert isinstance(scenario_dict[cls.TRACKS], dict)
        for obj_id, obj_state in scenario_dict[cls.TRACKS].items():
            cls._check_object_state_dict(
                obj_state, scenario_length=scenario_length, object_id=obj_id, valid_check=valid_check
            )
            # position heading check
            assert ScenarioDescription.HEADING in obj_state[ScenarioDescription.STATE
                                                            ], "heading is required for an object"
            assert ScenarioDescription.POSITION in obj_state[ScenarioDescription.STATE
                                                             ], "position is required for an object"

        # Check dynamic_map_state
        assert isinstance(scenario_dict[cls.DYNAMIC_MAP_STATES], dict)
        for obj_id, obj_state in scenario_dict[cls.DYNAMIC_MAP_STATES].items():
            cls._check_object_state_dict(obj_state, scenario_length=scenario_length, object_id=obj_id)

        # Check map features
        assert isinstance(scenario_dict[cls.MAP_FEATURES], dict)
        cls._check_map_features(scenario_dict[cls.MAP_FEATURES])

        # Check metadata
        assert isinstance(scenario_dict[cls.METADATA], dict)
        assert cls.METADATA_KEYS.issubset(set(scenario_dict[cls.METADATA].keys())), \
            "You lack these keys in metadata: {}".format(
                cls.METADATA_KEYS.difference(set(scenario_dict[cls.METADATA].keys()))
            )
        assert scenario_dict[cls.METADATA][cls.TIMESTEP].shape == (scenario_length, )
Check if the input scenario dict is self-consistent and has filled required fields.

        The required high-level fields include tracks, dynamic_map_states, metadata, map_features.
        For each object, the tracks[obj_id] should at least contain type, state, metadata.
        For each object, the tracks[obj_id]['state'] should at least contain position, heading.
        For each lane in map_features, map_feature[map_feat_id] should at least contain polyline.
        For metadata, it should at least contain metadrive_processed, coordinate and timestep.
        We have more checks to ensure the consistency of the data.

        Args:
            scenario_dict: the input dict.
            check_self_type: if True, assert the input dict is a native Python dict.
            valid_check: if True, we will assert the values for a given timestep are zeros if valid=False at that
                timestep.
        
metadrive/scenario/scenario_description.py