diff --git a/Scheduler/feature_scheduler/maintel/fbs_config_sit_survey_block_t345.py b/Scheduler/feature_scheduler/maintel/fbs_config_sit_survey_block_t345.py
new file mode 100644
index 00000000..724e9346
--- /dev/null
+++ b/Scheduler/feature_scheduler/maintel/fbs_config_sit_survey_block_t345.py
@@ -0,0 +1,194 @@
+# This file is part of ts_config_ocs.
+#
+# Developed for the Vera Rubin Observatory Telescope and Site System.
+# This product includes software developed by the LSST Project
+# (https://www.lsst.org).
+# See the COPYRIGHT file at the top-level directory of this distribution
+# for details of code ownership.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+import numpy as np
+from rubin_scheduler.scheduler import basis_functions, detailers, example, features
+from rubin_scheduler.scheduler.schedulers import CoreScheduler
+from rubin_scheduler.scheduler.surveys import BlobSurvey
+from rubin_scheduler.scheduler.utils import CurrentAreaMap, Footprint
+from rubin_scheduler.site_models import Almanac
+
+
+def get_scheduler():
+ nside = 32
+ science_program = "BLOCK-T345"
+ survey_start = 60653.5
+ camera_rot_limits = [-80, 80]
+
+ map_band_to_filtername = {
+ "u": "u_02",
+ "g": "g_01",
+ "r": "r_03",
+ "i": "i_06",
+ "z": "z_03",
+ "y": "y_04",
+ }
+
+ filtername = map_band_to_filtername["r"]
+ filtername2 = map_band_to_filtername["g"]
+
+ # Masks are fine - no band specific information.
+ mask_basis_functions = example.standard_masks(
+ nside=nside,
+ # Let's avoid the moon by this many degrees
+ moon_distance=30.0,
+ # Erik says to make wind speed minor so set limit high
+ wind_speed_maximum=50.0,
+ # I think these are the values appropriate for alt limits now?
+ min_alt=40,
+ max_alt=70,
+ min_az=220,
+ max_az=360,
+ # Avoid going into avoidance regions 30 minutes into the future
+ shadow_minutes=30,
+ )
+ # Mask basis functions have zero weights.
+ mask_basis_functions_weights = [0 for mask in mask_basis_functions]
+
+ # Set up footprint stuff here instead of in rubin_scheduler.
+ # Use the Almanac to find the position of the sun at the start of survey.
+ almanac = Almanac(mjd_start=survey_start)
+ sun_moon_info = almanac.get_sun_moon_positions(survey_start)
+ sun_ra_start = sun_moon_info["sun_RA"].copy()
+ # So this is a dictionary of filternames : int.
+ filterdict = {}
+ for i, f in enumerate(map_band_to_filtername.values()):
+ filterdict[f] = i
+ footprints = Footprint(
+ filters=filterdict,
+ mjd_start=survey_start,
+ sun_ra_start=sun_ra_start,
+ nside=nside,
+ )
+ # need to remap this to filtername not band
+ footprint = CurrentAreaMap(nside=nside)
+ footprint_hp, labels = footprint.return_maps()
+ new_dtype = np.dtype([(map_band_to_filtername[f], " 0] + [
+ (i[0], i[1]) for i in rf2 if i[1] > 0
+ ]
+ # Remove the M5Diff basis functions as unusable at present
+ reward_functions = [
+ (bf, weight)
+ for (bf, weight) in reward_functions
+ if not isinstance(bf, basis_functions.M5DiffBasisFunction)
+ ]
+
+ # unpack the basis functions and weights
+ reward_basis_functions_weights = [val[1] for val in reward_functions]
+ reward_basis_functions = [val[0] for val in reward_functions]
+
+ # Set up blob surveys.
+ pair_time = 20
+ if filtername2 is None:
+ survey_name = "simple pair %i, %s" % (pair_time, filtername)
+ else:
+ survey_name = "simple pair %i, %s%s" % (pair_time, filtername, filtername2)
+
+ # Set up detailers for each requested observation.
+ detailer_list = []
+ # Avoid camera rotator limits.
+ detailer_list.append(
+ detailers.CameraRotDetailer(
+ min_rot=np.min(camera_rot_limits), max_rot=np.max(camera_rot_limits)
+ )
+ )
+ # Reorder visits in a blob so that closest to current altitude is first.
+ detailer_list.append(detailers.CloseAltDetailer())
+ # Add a detailer to label visits as either first or second of the pair.
+ if filtername2 is not None:
+ detailer_list.append(detailers.TakeAsPairsDetailer(filtername=filtername2))
+
+ # Set up the survey.
+ ignore_obs = ["DD"]
+
+ BlobSurvey_params = {
+ "slew_approx": 7.5,
+ "filter_change_approx": 140.0,
+ "read_approx": 2.4,
+ "flush_time": pair_time * 3,
+ "smoothing_kernel": None,
+ "nside": nside,
+ "seed": 42,
+ "dither": True,
+ "twilight_scale": False,
+ }
+
+ pair_survey = BlobSurvey(
+ reward_basis_functions + mask_basis_functions,
+ reward_basis_functions_weights + mask_basis_functions_weights,
+ filtername1=filtername,
+ filtername2=filtername2,
+ exptime=150,
+ ideal_pair_time=pair_time,
+ survey_name=survey_name,
+ ignore_obs=ignore_obs,
+ nexp=1,
+ detailers=detailer_list,
+ science_program=science_program,
+ **BlobSurvey_params,
+ )
+
+ # Tucking this here so we can look at how many observations
+ # recorded for this survey and what was the last one.
+ pair_survey.extra_features["ObsRecorded"] = features.NObsCount()
+ pair_survey.extra_features["LastObs"] = features.LastObservation()
+
+ scheduler = CoreScheduler([pair_survey], nside=nside)
+ return nside, scheduler
+
+
+if __name__ == "config":
+ nside, scheduler = get_scheduler()
diff --git a/Scheduler/observing_blocks_maintel/AOS/BLOCK-T345.json b/Scheduler/observing_blocks_maintel/AOS/BLOCK-T345.json
new file mode 100644
index 00000000..b61a4b80
--- /dev/null
+++ b/Scheduler/observing_blocks_maintel/AOS/BLOCK-T345.json
@@ -0,0 +1,79 @@
+{
+ "name": "AOSSurveyMode",
+ "program": "BLOCK-T345",
+ "constraints": [],
+ "scripts": [
+ {
+ "name": "maintel/track_target.py",
+ "standard": true,
+ "parameters": {
+ "target_name": "$name",
+ "slew_icrs": {
+ "ra": "$ra",
+ "dec": "$dec"
+ },
+ "rot_value": "$rot",
+ "rot_type": "PhysicalSky",
+ "az_wrap_strategy": "NOUNWRAP"
+ }
+ },
+ {
+ "name": "maintel/close_loop_comcam.py",
+ "standard": true,
+ "parameters": {
+ "exposure_time": 15,
+ "max_iter": 1,
+ "gain_sequence": [
+ 0.5
+ ],
+ "mode": "FAM",
+ "program": "$program",
+ "note": "closed_loop_aos_survey_mode",
+ "reason": "aos_survey_mode",
+ "filter": "$band_filter",
+ "used_dofs": [
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23,
+ 28,
+ 29,
+ 30,
+ 31,
+ 32,
+ 33,
+ 34,
+ 37,
+ 38,
+ 39,
+ 40,
+ 41,
+ 42,
+ 45,
+ 46
+ ],
+ "apply_corrections": true,
+ "use_ocps": true
+ }
+ }
+ ],
+ "configuration_schema": ""
+}
\ No newline at end of file
diff --git a/Scheduler/v7/maintel_fbs_sit_block_t345.yaml b/Scheduler/v7/maintel_fbs_sit_block_t345.yaml
new file mode 100644
index 00000000..df2b096e
--- /dev/null
+++ b/Scheduler/v7/maintel_fbs_sit_block_t345.yaml
@@ -0,0 +1,47 @@
+maintel:
+ driver_type: feature_scheduler
+ mode: ADVANCE
+ startup_type: COLD
+ startup_database: /home/saluser/rubin_sim_data/fbs_observation_database_maintel.sql
+ instrument_name: CCCamera
+ models:
+ observatory_model:
+ camera:
+ filter_max_changes_burst_num: 1000000
+ filter_max_changes_avg_num: 30000
+ optics_loop_corr:
+ tel_optics_cl_alt_limit:
+ - 0
+ - 60
+ - 90
+ park:
+ filter_position: r_03
+ driver_configuration:
+ parameters:
+ night_boundary: -10.0
+ stop_tracking_observing_script_name: maintel/stop_tracking.py
+ feature_scheduler_driver_configuration:
+ observation_database_name: /home/saluser/rubin_sim_data/fbs_observation_database_maintel.sql
+ scheduler_config: /net/obs-env/auto_base_packages/ts_config_ocs/Scheduler/feature_scheduler/maintel/fbs_config_sit_survey_block_t345.py
+ telemetry:
+ streams:
+ - name: seeing
+ efd_table: lsst.sal.DIMM.logevent_dimmMeasurement
+ efd_columns:
+ - fwhm
+ efd_delta_time: 300.0
+ fill_value: 1.0
+ - name: wind_speed
+ efd_table: lsst.sal.ESS.airFlow
+ efd_columns:
+ - speed
+ efd_delta_time: 300.0
+ fill_value: 0.0
+ csc_index: 301
+ - name: wind_direction
+ efd_table: lsst.sal.ESS.airFlow
+ efd_columns:
+ - direction
+ efd_delta_time: 300.0
+ fill_value: 0.0
+ csc_index: 301