Exemplo n.º 1
0
    def test_visible_above_horizon(self):
        """
        visible_above_horizon test
        """
        #equitorial orbit
        tle_line1 = "1 44235U 19029A   20178.66667824  .02170155  00000-0  40488-1 0  9998"
        tle_line2 = "2 44235  00.0000 163.9509 0005249 306.3756  83.0170 15.45172567 61683"
        #high inclination orbit
        tle2_line1 = "1 44235U 19029A   20178.66667824  .02170155  00000-0  40488-1 0  9998"
        tle2_line2 = "2 44235  70.0000 163.9509 0005249 306.3756  83.0170 15.45172567 61683"
        prop1 = orekit_utils.str_tle_propagator(tle_line1, tle_line2)
        prop2 = orekit_utils.str_tle_propagator(tle2_line1, tle2_line2)
        time = AbsoluteDate(2020, 6, 26, 1, 40, 00.000,
                            TimeScalesFactory.getUTC())

        #verified with graphing overviews
        self.assertFalse(orekit_utils.visible_above_horizon(
            prop1, prop2, time))
        self.assertTrue(
            orekit_utils.visible_above_horizon(prop1, prop2,
                                               time.shiftedBy(60. * 10.)))
        self.assertTrue(
            orekit_utils.visible_above_horizon(
                prop1, prop2, time.shiftedBy(60. * 10. + 45. * 60.)))
        time_period_visible = orekit_utils.visible_above_horizon(
            prop1, prop2, time, 60 * 30)[0]
        self.assertTrue(
            time.shiftedBy(60. * 10.).isBetween(time_period_visible[0],
                                                time_period_visible[1]))
Exemplo n.º 2
0
 def test_check_iot_in_range(self):
     """
     check_iot_in_range test
     """
     tle_line1 = "1 44235U 19029A   20178.66667824  .02170155  00000-0  40488-1 0  9998"
     tle_line2 = "2 44235  00.0000 163.9509 0005249 306.3756  270.0170 15.45172567 61683"
     prop1 = orekit_utils.str_tle_propagator(tle_line1, tle_line2)
     lat = 0.
     lon = 0.
     alt = 10.
     time = AbsoluteDate(2020, 6, 26, 1, 40, 00.000, TimeScalesFactory.getUTC())
     self.assertTrue(check_iot_in_range(prop1, lat, lon, alt, time))
     self.assertFalse(check_iot_in_range(prop1, lat, lon, alt, time.shiftedBy(60.*30.)))
Exemplo n.º 3
0
    def get_sun_max_elevation(self, year, month, day):
        """
        Returns the maximum elevation angle (in radians) of the Sun (that is the zenith) a given day.

        Parameters
        ----------
        year : int
            Year.
        month : int
            Month.
        day : int
            Day.

        Returns
        -------
        current_ele0 : TYPE
            DESCRIPTION.
        currentutc_date : TYPE
            DESCRIPTION.

        """
        currentutc_date = AbsoluteDate(year, month, day, 0, 0, 0.0,
                                       TimeScalesFactory.getUTC())
        is_max_elevation = False
        time_step = 10.0
        current_ele0 = self.get_sun_elevation(currentutc_date)
        current_ele1 = self.get_sun_elevation(
            currentutc_date.shiftedBy(time_step))
        if current_ele0 > current_ele1:
            is_max_elevation = True
        while not is_max_elevation:
            current_ele0 = current_ele1
            current_ele1 = self.get_sun_elevation(
                currentutc_date.shiftedBy(time_step))
            if current_ele0 > current_ele1:
                is_max_elevation = True
                currentutc_date.shiftedBy(-time_step)
            currentutc_date = currentutc_date.shiftedBy(time_step)
        return current_ele0, currentutc_date
Exemplo n.º 4
0
class Environment():
    """
    Simulation environment.

    This environment is used to propagate trajectories and render images at
    each simulation step.
    """

    def __init__(self,
                 res_dir,
                 starcat_dir,
                 instrument,
                 with_infobox,
                 with_clipping,
                 sssb,
                 sun,
                 lightref,
                 encounter_date,
                 duration,
                 frames,
                 encounter_distance,
                 relative_velocity,
                 with_sunnyside,
                 with_terminator,
                 timesampler_mode,
                 slowmotion_factor,
                 exposure,
                 samples,
                 device,
                 tile_size,
                 oneshot=False,
                 spacecraft=None,
                 opengl_renderer=False):

        self.opengl_renderer = opengl_renderer
        self.brdf_params = sssb.get('brdf_params', None)

        self.root_dir = Path(__file__).parent.parent.parent
        data_dir = self.root_dir / "data"
        self.models_dir = utils.check_dir(data_dir / "models")

        self.res_dir = res_dir
        
        self.starcat_dir = starcat_dir

        self.inst = sc.Instrument(instrument)

        self.ts = TimeScalesFactory.getTDB()
        self.ref_frame = FramesFactory.getICRF()
        self.mu_sun = Constants.IAU_2015_NOMINAL_SUN_GM

        encounter_date = encounter_date
        self.encounter_date = AbsoluteDate(int(encounter_date["year"]),
                                           int(encounter_date["month"]),
                                           int(encounter_date["day"]),
                                           int(encounter_date["hour"]),
                                           int(encounter_date["minutes"]),
                                           float(encounter_date["seconds"]),
                                           self.ts)
        self.duration = duration
        self.start_date = self.encounter_date.shiftedBy(-self.duration / 2.)
        self.end_date = self.encounter_date.shiftedBy(self.duration / 2.)

        self.frames = frames

        self.minimum_distance = encounter_distance
        self.relative_velocity = relative_velocity
        self.with_terminator = bool(with_terminator)
        self.with_sunnyside = bool(with_sunnyside)
        self.timesampler_mode = timesampler_mode
        self.slowmotion_factor = slowmotion_factor

        self.render_settings = dict()
        self.render_settings["exposure"] = exposure
        self.render_settings["samples"] = samples
        self.render_settings["device"] = device
        self.render_settings["tile"] = tile_size

        self.sssb_settings = sssb
        self.with_infobox = with_infobox
        self.with_clipping = with_clipping

        # Setup rendering engine (renderer)
        self.setup_renderer()

        # Setup SSSB
        self.setup_sssb(sssb)

        # Setup SC
        self.setup_spacecraft(spacecraft, oneshot=oneshot)

        if not self.opengl_renderer:
            # Setup Sun
            self.setup_sun(sun)

            # Setup Lightref
            self.setup_lightref(lightref)

        logger.debug("Init finished")

    def setup_renderer(self):
        """Create renderer, apply common settings and create sc cam."""

        render_dir = utils.check_dir(self.res_dir)
        raw_dir = utils.check_dir(render_dir / "raw")

        if self.opengl_renderer:
            from .opengl import rendergl
            self.renderer = rendergl.RenderController(render_dir, stardb_path=self.starcat_dir)
            self.renderer.create_scene("SssbOnly")
        else:
            from .render import BlenderController
            self.renderer = BlenderController(render_dir,
                                              raw_dir,
                                              self.starcat_dir,
                                              self.inst,
                                              self.sssb_settings,
                                              self.with_infobox,
                                              self.with_clipping)

        self.renderer.create_camera("ScCam")

        self.renderer.configure_camera("ScCam", 
                                       self.inst.focal_l,
                                       self.inst.chip_w)

        if not self.opengl_renderer:
            self.renderer.create_scene("SssbConstDist")
            self.renderer.create_camera("SssbConstDistCam", scenes="SssbConstDist")
            self.renderer.configure_camera("SssbConstDistCam",
                                           self.inst.focal_l,
                                           self.inst.chip_w)

            self.renderer.create_scene("LightRef")
            self.renderer.create_camera("LightRefCam", scenes="LightRef")
            self.renderer.configure_camera("LightRefCam",
                                           self.inst.focal_l,
                                           self.inst.chip_w)
        else:
            # as use sispo cam model
            self.renderer.set_scene_config({
                'debug': False,
                'flux_only': False,
                'sispo_cam': self.inst,         # use sispo cam model instead 
                                                #of own (could use own if can give exposure & gain)
                'stars': True,                  # use own star db
                'lens_effects': False,          # includes the sun
                'brdf_params': self.brdf_params,
            })

        self.renderer.set_device(self.render_settings["device"], 
                                 self.render_settings["tile"])
        self.renderer.set_samples(self.render_settings["samples"])
        self.renderer.set_exposure(self.render_settings["exposure"])
        self.renderer.set_resolution(self.inst.res)
        self.renderer.set_output_format()

    def setup_sun(self, settings):
        """Create Sun and respective render object."""
        sun_model_file = Path(settings["model"]["file"])

        try:
            sun_model_file = sun_model_file.resolve()
        except OSError as e:
            raise SimulationError(e)

        if not sun_model_file.is_file():
                sun_model_file = self.models_dir / sun_model_file.name
                sun_model_file = sun_model_file.resolve()
        
        if not sun_model_file.is_file():
            raise SimulationError("Given SSSB model filename does not exist.")

        self.sun = cb.CelestialBody(settings["model"]["name"],
                                 model_file=sun_model_file)
        self.sun.render_obj = self.renderer.load_object(self.sun.model_file,
                                                        self.sun.name)

    def setup_sssb(self, settings):
        """Create SmallSolarSystemBody and respective blender object."""
        sssb_model_file = Path(settings["model"]["file"])

        try:
            sssb_model_file = sssb_model_file.resolve()
        except OSError as e:
            raise SimulationError(e)

        if not sssb_model_file.is_file():
                sssb_model_file = self.models_dir / sssb_model_file.name
                sssb_model_file = sssb_model_file.resolve()
        
        if not sssb_model_file.is_file():
            raise SimulationError("Given SSSB model filename does not exist.")

        self.sssb = sssb.SmallSolarSystemBody(settings["model"]["name"],
                                              self.mu_sun, 
                                              settings["trj"],
                                              settings["att"],
                                              model_file=sssb_model_file)
        self.sssb.render_obj = self.renderer.load_object(
                                    self.sssb.model_file, 
                                    settings["model"]["name"], 
                                    ["SssbOnly"] + ([] if self.opengl_renderer else ["SssbConstDist"]))
        self.sssb.render_obj.rotation_mode = "AXIS_ANGLE"
        self.sssb.render_obj.location = (0.0, 0.0, 0.0)

        # Setup previously generated coma
        coma = settings.get('coma', None)
        if coma:
            with open(coma['file'], 'r') as fh:
                coma.update(json.load(fh))
            assert self.opengl_renderer, '"coma" setting under "sssb" is currently only supported for opengl rendering'
            sssb_rot = coma.get('sssb_rot', False)
            if not sssb_rot:
                # if param missing and one shot mode, assumes that coma is created with same asteroid orientation
                assert self.sssb.rot_history, 'SSSB rotation state for cached coma is not given with "sssb_rot"'
                sssb_rot = self.sssb.rot_history[0]
                sssb_rot = (sssb_rot.getAngle(), *sssb_rot.getAxis(RotationConvention.FRAME_TRANSFORM).toArray())

            self.sssb.coma = self.renderer.load_coma(
                coma['tiles_file'],
                coma['dimensions'],
                coma['resolution'],
                coma.get('intensity', 1e-4),
                sssb_rot
            )

    def setup_spacecraft(self, spacecraft=None, oneshot=False):
        """Create Spacecraft and respective blender object."""

        sc_state = None
        sc_rot_state = None
        if spacecraft is None:
            sssb_state = self.sssb.get_state(self.encounter_date)
            sc_state = sc.Spacecraft.calc_encounter_state(sssb_state,
                                                       self.minimum_distance,
                                                       self.relative_velocity,
                                                       self.with_terminator,
                                                       self.with_sunnyside)
        else:
            if 'r' in spacecraft:
                sc_state = PVCoordinates(Vector3D(spacecraft['r']), 
                                         Vector3D(spacecraft.get('v', [0.0, 0.0, 0.0])))
            if 'angleaxis' in spacecraft:
                sc_pxpz_rot = Rotation(Vector3D(spacecraft['angleaxis'][1:4]),
                                       spacecraft['angleaxis'][0],
                                       RotationConvention.FRAME_TRANSFORM)

                # transform camera where +x is forward and +z is up into -z is forward and +y is up
                mzpy_rot = self.pxpz_to_mzpy(sc_pxpz_rot)
                sc_rot_state = AngularCoordinates(mzpy_rot, Vector3D(0., 0., 0.))

        self.spacecraft = sc.Spacecraft("CI",
                                     self.mu_sun,
                                     sc_state,
                                     self.encounter_date,
                                     rot_state=sc_rot_state,
                                     oneshot=oneshot)

    @staticmethod
    def pxpz_to_mzpy(pxpz_rot):
        pxpz_to_mzpy_rot = Rotation(0.5, 0.5, -0.5, -0.5, False)
        return pxpz_to_mzpy_rot.applyTo(pxpz_rot)

    @staticmethod
    def mzpy_to_pxpz(mzpy_rot):
        pxpz_to_mzpy_rot = Rotation(0.5, 0.5, -0.5, -0.5, False)
        return pxpz_to_mzpy_rot.applyInverseTo(mzpy_rot)

    def setup_lightref(self, settings):
        """Create lightreference blender object."""
        lightref_model_file = Path(settings["model"]["file"])

        try:
            lightref_model_file = lightref_model_file.resolve()
        except OSError as e:
            raise SimulationError(e)

        if not lightref_model_file.is_file():
                lightref_model_file = self.models_dir / lightref_model_file.name
                lightref_model_file = lightref_model_file.resolve()
        
        if not lightref_model_file.is_file():
            raise SimulationError("Given lightref model filename does not exist.")

        self.lightref = self.renderer.load_object(lightref_model_file,
                                                  settings["model"]["name"],
                                                  scenes="LightRef")
        self.lightref.location = (0.0, 0.0, 0.0)

    def simulate(self):
        """Do simulation."""
        logger.debug("Starting simulation")

        logger.debug("Propagating SSSB")
        self.sssb.propagate(self.start_date,
                            self.end_date,
                            self.frames,
                            self.timesampler_mode,
                            self.slowmotion_factor)

        logger.debug("Propagating Spacecraft")
        self.spacecraft.propagate(self.start_date,
                                  self.end_date,
                                  self.frames,
                                  self.timesampler_mode,
                                  self.slowmotion_factor)

        logger.debug("Simulation completed")
        self.save_results()

    def render(self):
        """Render simulation scenario."""
        logger.debug("Rendering simulation")
        scaling = 1. if self.opengl_renderer else 1000.
        N = len(self.spacecraft.date_history)

        # Render frame by frame
        print("Rendering in progress...")
        for i, (date, sc_pos, sc_rot, sssb_pos, sssb_rot) in enumerate(zip(
                                                                   self.spacecraft.date_history,
                                                                   self.spacecraft.pos_history,
                                                                   self.spacecraft.rot_history,
                                                                   self.sssb.pos_history,
                                                                   self.sssb.rot_history)):

            date_str = datetime.strptime(date.toString(), "%Y-%m-%dT%H:%M:%S.%f")
            date_str = date_str.strftime("%Y-%m-%dT%H%M%S-%f")

            # metadict creation
            metainfo = dict()
            metainfo["sssb_pos"] = np.asarray(sssb_pos.toArray())
            metainfo["sc_pos"] = np.asarray(sc_pos.toArray())
            metainfo["distance"] = sc_pos.distance(sssb_pos)
            metainfo["date"] = date_str

            # Set Rotation
            angle, axis = convert_rot_to_angle_axis(sssb_rot, RotationConvention.FRAME_TRANSFORM)
            self.renderer.set_object_rot(angle, axis , self.sssb.render_obj)

            # Update environment
            # Removed unnecessary conditional, opengl can omit the scaling
            self.renderer.set_sun_location(-np.asarray(sssb_pos.toArray()), 
                                            scaling, getattr(self,"sun", None))

            # Update sssb and spacecraft
            pos_sc_rel_sssb = np.asarray(sc_pos.subtract(sssb_pos).toArray()) / scaling
            self.renderer.set_camera_location("ScCam", pos_sc_rel_sssb)
            if self.spacecraft.auto_targeting:
                self.renderer.target_camera(self.sssb.render_obj, "ScCam")
            else:
                angle, axis = convert_rot_to_angle_axis(sc_rot, RotationConvention.FRAME_TRANSFORM)
                self.renderer.set_camera_rot(angle, axis, "ScCam")

            if not self.opengl_renderer:
                # Update scenes/cameras
                pos_cam_const_dist = pos_sc_rel_sssb * scaling / np.sqrt(
                                        np.dot(pos_sc_rel_sssb, pos_sc_rel_sssb))
                self.renderer.set_camera_location("SssbConstDistCam", pos_cam_const_dist)
                self.renderer.target_camera(self.sssb.render_obj, "SssbConstDistCam")

                lightrefcam_pos = -np.asarray(sssb_pos.toArray()) * scaling \
                                  / np.sqrt(np.dot(np.asarray(sssb_pos.toArray()), 
                                    np.asarray(sssb_pos.toArray())))
                self.renderer.set_camera_location("LightRefCam", lightrefcam_pos)
                self.renderer.target_camera(self.sun.render_obj, "CalibrationDisk")
                self.renderer.target_camera(self.lightref, "LightRefCam")

            # Render blender scenes
            self.renderer.render(metainfo)

            print('%d/%d' % (i+1, N))

        logger.debug("Rendering completed")

    def save_results(self):
        """Save simulation results to a file."""
        logger.debug("Saving propagation results")

        float_formatter = "{:.16f}".format
        np.set_printoptions(formatter={'float_kind': float_formatter})
        vec2str = lambda v: str(np.asarray(v.toArray()))

        print_list = [
            [str(v) for v in self.spacecraft.date_history],
            [vec2str(v) for v in self.spacecraft.pos_history],
            [vec2str(v) for v in self.spacecraft.vel_history],
            #[vec2str(v) for v in self.spacecraft.rot_history],
            [vec2str(v) for v in self.sssb.pos_history],
            [vec2str(v) for v in self.sssb.vel_history],
            #[vec2str(v) for v in self.sssb.rot_history],
        ]

        with open(str(self.res_dir / "DynamicsHistory.txt"), "w+") as file:
            for i in range(len(self.spacecraft.date_history)):
                line = "\t".join([v[i] for v in print_list]) + "\n"
                file.write(line)

        logger.debug("Propagation results saved")
Exemplo n.º 5
0

class Propagator:
    def __init__(self, initial_orbit, initial_date, shifted_date):
        self.shifted_date = shifted_date
        self.initial_orbit = initial_orbit
        self.initial_date = initial_date

    def __str__(self):
        return str(self.__dict__)

    def propagate_keplerian_elements(self):
        propagator = KeplerianPropagator(self.initial_orbit)
        return propagator.propagate(self.initial_date, self.shifted_date)


if __name__ == "__main__":
    instance = KeplerianElements(
        24464560.0, 0.7311, 0.122138, 3.10686, 1.00681, 0.048363,
        PositionAngle.MEAN, FramesFactory.getEME2000(),
        AbsoluteDate(2020, 1, 1, 0, 0, 00.000,
                     TimeScalesFactory.getUTC()), Constants.GRS80_EARTH_MU)
    k = instance.init_keplerian_elements()
    init_date = AbsoluteDate(2020, 1, 1, 0, 0, 00.000,
                             TimeScalesFactory.getUTC())
    shift = init_date.shiftedBy(3600.0 * 48)
    kp = Propagator(k, init_date, shift)
    kp.propagate_keplerian_elements()
    print(k)
    print(kp)
Exemplo n.º 6
0
def main():

    a = 24396159.0  # semi major axis (m)
    e = 0.720  # eccentricity
    i = radians(10.0)  # inclination
    omega = radians(50.0)  # perigee argument
    raan = radians(150)  # right ascension of ascending node
    lM = 0.0  # mean anomaly

    # Set inertial frame
    inertialFrame = FramesFactory.getEME2000()

    # Initial date in UTC time scale
    utc = TimeScalesFactory.getUTC()
    initial_date = AbsoluteDate(2004, 1, 1, 23, 30, 00.000, utc)

    # Setup orbit propagator
    # gravitation coefficient
    mu = 3.986004415e+14

    # Orbit construction as Keplerian
    initialOrbit = KeplerianOrbit(a, e, i, omega, raan, lM, PositionAngle.MEAN,
                                  inertialFrame, initial_date, mu)

    initial_state = SpacecraftState(initialOrbit)

    # use a numerical propogator
    min_step = 0.001
    max_step = 1000.0
    position_tolerance = 10.0

    propagation_type = OrbitType.KEPLERIAN
    tolerances = NumericalPropagator.tolerances(position_tolerance,
                                                initialOrbit, propagation_type)

    integrator = DormandPrince853Integrator(min_step, max_step, 1e-5, 1e-10)

    propagator = NumericalPropagator(integrator)
    propagator.setOrbitType(propagation_type)

    # force model gravity field
    provider = GravityFieldFactory.getNormalizedProvider(10, 10)
    holmesFeatherstone = HolmesFeatherstoneAttractionModel(
        FramesFactory.getITRF(IERSConventions.IERS_2010, True), provider)

    # SRP
    # ssc = IsotropicRadiationSingleCoefficient(100.0, 0.8)  # Spacecraft surface area (m^2), C_r absorbtion
    # srp = SolarRadiationPressure(CelestialBodyFactory.getSun(), a, ssc)  # sun, semi-major Earth, spacecraft sensitivity

    propagator.addForceModel(holmesFeatherstone)
    # propagator.addForceModel(ThirdBodyAttraction(CelestialBodyFactory.getSun()))
    # propagator.addForceModel(ThirdBodyAttraction(CelestialBodyFactory.getMoon()))
    # propagator.addForceModel(srp)

    propagator.setMasterMode(60.0, TutorialStepHandler())

    propagator.setInitialState(initial_state)

    # propagator.setEphemerisMode()

    finalstate = propagator.propagate(initial_date.shiftedBy(
        10. * 24 * 60**2))  # TIme shift in seconds
Exemplo n.º 7
0
class Environment():
    """
    Simulation environment.

    This environment is used to propagate trajectories and render images at
    each simulation step.
    """
    def __init__(self,
                 res_dir,
                 starcat_dir,
                 instrument,
                 with_infobox,
                 with_clipping,
                 sssb,
                 sun,
                 lightref,
                 encounter_date,
                 duration,
                 frames,
                 encounter_distance,
                 relative_velocity,
                 with_sunnyside,
                 with_terminator,
                 timesampler_mode,
                 slowmotion_factor,
                 exposure,
                 samples,
                 device,
                 tile_size,
                 ext_logger=None):

        if ext_logger is not None:
            self.logger = ext_logger
        else:
            self.logger = utils.create_logger()

        self.root_dir = Path(__file__).parent.parent.parent
        data_dir = self.root_dir / "data"
        self.models_dir = utils.check_dir(data_dir / "models")

        self.res_dir = res_dir

        self.starcat_dir = starcat_dir

        self.inst = Instrument(instrument)

        self.ts = TimeScalesFactory.getTDB()
        self.ref_frame = FramesFactory.getICRF()
        self.mu_sun = Constants.IAU_2015_NOMINAL_SUN_GM

        encounter_date = encounter_date
        self.encounter_date = AbsoluteDate(int(encounter_date["year"]),
                                           int(encounter_date["month"]),
                                           int(encounter_date["day"]),
                                           int(encounter_date["hour"]),
                                           int(encounter_date["minutes"]),
                                           float(encounter_date["seconds"]),
                                           self.ts)
        self.duration = duration
        self.start_date = self.encounter_date.shiftedBy(-self.duration / 2.)
        self.end_date = self.encounter_date.shiftedBy(self.duration / 2.)

        self.frames = frames

        self.minimum_distance = encounter_distance
        self.relative_velocity = relative_velocity
        self.with_terminator = bool(with_terminator)
        self.with_sunnyside = bool(with_sunnyside)
        self.timesampler_mode = timesampler_mode
        self.slowmotion_factor = slowmotion_factor

        self.render_settings = dict()
        self.render_settings["exposure"] = exposure
        self.render_settings["samples"] = samples
        self.render_settings["device"] = device
        self.render_settings["tile"] = tile_size

        self.sssb_settings = sssb
        self.with_infobox = with_infobox
        self.with_clipping = with_clipping

        # Setup rendering engine (renderer)
        self.setup_renderer()

        # Setup Sun
        self.setup_sun(sun)

        # Setup SSSB
        self.setup_sssb(sssb)

        # Setup SC
        self.setup_spacecraft()

        # Setup Lightref
        self.setup_lightref(lightref)

    def setup_renderer(self):
        """Create renderer, apply common settings and create sc cam."""

        render_dir = utils.check_dir(self.res_dir)
        raw_dir = utils.check_dir(render_dir / "raw")

        self.renderer = render.BlenderController(render_dir,
                                                 raw_dir,
                                                 self.starcat_dir,
                                                 self.inst,
                                                 self.sssb_settings,
                                                 self.with_infobox,
                                                 self.with_clipping,
                                                 ext_logger=self.logger)
        self.renderer.create_camera("ScCam")
        self.renderer.configure_camera("ScCam", self.inst.focal_l,
                                       self.inst.chip_w)

        self.renderer.create_scene("SssbConstDist")
        self.renderer.create_camera("SssbConstDistCam", scenes="SssbConstDist")
        self.renderer.configure_camera("SssbConstDistCam", self.inst.focal_l,
                                       self.inst.chip_w)

        self.renderer.create_scene("LightRef")
        self.renderer.create_camera("LightRefCam", scenes="LightRef")
        self.renderer.configure_camera("LightRefCam", self.inst.focal_l,
                                       self.inst.chip_w)

        self.renderer.set_device(self.render_settings["device"],
                                 self.render_settings["tile"])
        self.renderer.set_samples(self.render_settings["samples"])
        self.renderer.set_exposure(self.render_settings["exposure"])
        self.renderer.set_resolution(self.inst.res)
        self.renderer.set_output_format()

    def setup_sun(self, settings):
        """Create Sun and respective render object."""
        sun_model_file = Path(settings["model"]["file"])

        try:
            sun_model_file = sun_model_file.resolve()
        except OSError as e:
            raise SimulationError(e)

        if not sun_model_file.is_file():
            sun_model_file = self.models_dir / sun_model_file.name
            sun_model_file = sun_model_file.resolve()

        if not sun_model_file.is_file():
            raise SimulationError("Given SSSB model filename does not exist.")

        self.sun = CelestialBody(settings["model"]["name"],
                                 model_file=sun_model_file)
        self.sun.render_obj = self.renderer.load_object(
            self.sun.model_file, self.sun.name)

    def setup_sssb(self, settings):
        """Create SmallSolarSystemBody and respective blender object."""
        sssb_model_file = Path(settings["model"]["file"])

        try:
            sssb_model_file = sssb_model_file.resolve()
        except OSError as e:
            raise SimulationError(e)

        if not sssb_model_file.is_file():
            sssb_model_file = self.models_dir / sssb_model_file.name
            sssb_model_file = sssb_model_file.resolve()

        if not sssb_model_file.is_file():
            raise SimulationError("Given SSSB model filename does not exist.")

        self.sssb = SmallSolarSystemBody(settings["model"]["name"],
                                         self.mu_sun,
                                         settings["trj"],
                                         settings["att"],
                                         model_file=sssb_model_file)
        self.sssb.render_obj = self.renderer.load_object(
            self.sssb.model_file, settings["model"]["name"],
            ["SssbOnly", "SssbConstDist"])
        self.sssb.render_obj.rotation_mode = "AXIS_ANGLE"

    def setup_spacecraft(self):
        """Create Spacecraft and respective blender object."""
        sssb_state = self.sssb.get_state(self.encounter_date)
        sc_state = Spacecraft.calc_encounter_state(sssb_state,
                                                   self.minimum_distance,
                                                   self.relative_velocity,
                                                   self.with_terminator,
                                                   self.with_sunnyside)
        self.spacecraft = Spacecraft("CI", self.mu_sun, sc_state,
                                     self.encounter_date)

    def setup_lightref(self, settings):
        """Create lightreference blender object."""
        lightref_model_file = Path(settings["model"]["file"])

        try:
            lightref_model_file = lightref_model_file.resolve()
        except OSError as e:
            raise SimulationError(e)

        if not lightref_model_file.is_file():
            lightref_model_file = self.models_dir / lightref_model_file.name
            lightref_model_file = lightref_model_file.resolve()

        if not lightref_model_file.is_file():
            raise SimulationError("Given SSSB model filename does not exist.")

        self.lightref = self.renderer.load_object(lightref_model_file,
                                                  settings["model"]["name"],
                                                  scenes="LightRef")
        self.lightref.location = (0, 0, 0)

    def simulate(self):
        """Do simulation."""
        self.logger.debug("Starting simulation")

        self.logger.debug("Propagating SSSB")
        self.sssb.propagate(self.start_date, self.end_date, self.frames,
                            self.timesampler_mode, self.slowmotion_factor)

        self.logger.debug("Propagating Spacecraft")
        self.spacecraft.propagate(self.start_date, self.end_date, self.frames,
                                  self.timesampler_mode,
                                  self.slowmotion_factor)

        self.logger.debug("Simulation completed")
        self.save_results()

    def set_rotation(self, sssb_rot, sispoObj):
        """Set rotation and returns original transformation matrix"""
        """Assumes that the blender scaling is set to 1"""
        #sssb_axis = sssb_rot.getAxis(self.sssb.rot_conv)
        sssb_angle = sssb_rot.getAngle()

        eul0 = mathutils.Euler((0.0, 0.0, sssb_angle), 'XYZ')
        eul1 = mathutils.Euler((0.0, sispoObj.Dec, 0.0), 'XYZ')
        eul2 = mathutils.Euler((0.0, 0.0, sispoObj.RA), 'XYZ')

        R0 = eul0.to_matrix()
        R1 = eul1.to_matrix()
        R2 = eul2.to_matrix()

        M = R2 @ R1 @ R0

        original_transform = sispoObj.render_obj.matrix_world

        sispoObj.render_obj.matrix_world = M.to_4x4()
        return original_transform

    def render(self):
        """Render simulation scenario."""
        self.logger.debug("Rendering simulation")

        # Render frame by frame
        for (date, sc_pos, sssb_pos,
             sssb_rot) in zip(self.spacecraft.date_history,
                              self.spacecraft.pos_history,
                              self.sssb.pos_history, self.sssb.rot_history):

            date_str = datetime.strptime(date.toString(),
                                         "%Y-%m-%dT%H:%M:%S.%f")
            date_str = date_str.strftime("%Y-%m-%dT%H%M%S-%f")

            # metadict creation
            metainfo = dict()
            metainfo["sssb_pos"] = np.asarray(sssb_pos.toArray())
            metainfo["sc_pos"] = np.asarray(sc_pos.toArray())
            metainfo["distance"] = sc_pos.distance(sssb_pos)
            metainfo["date"] = date_str

            self.set_rotation(sssb_rot, self.sssb)

            # Update environment
            self.sun.render_obj.location = -np.asarray(
                sssb_pos.toArray()) / 1000.

            # Update sssb and spacecraft
            pos_sc_rel_sssb = np.asarray(
                sc_pos.subtract(sssb_pos).toArray()) / 1000.
            self.renderer.set_camera_location("ScCam", pos_sc_rel_sssb)

            self.renderer.target_camera(self.sssb.render_obj, "ScCam")

            # Update scenes/cameras
            pos_cam_const_dist = pos_sc_rel_sssb * 1000. / np.sqrt(
                np.dot(pos_sc_rel_sssb, pos_sc_rel_sssb))
            self.renderer.set_camera_location("SssbConstDistCam",
                                              pos_cam_const_dist)
            self.renderer.target_camera(self.sssb.render_obj,
                                        "SssbConstDistCam")

            lightrefcam_pos = -np.asarray(
                sssb_pos.toArray()) * 1000. / np.sqrt(
                    np.dot(np.asarray(sssb_pos.toArray()),
                           np.asarray(sssb_pos.toArray())))
            self.renderer.set_camera_location("LightRefCam", lightrefcam_pos)
            self.renderer.target_camera(self.sun.render_obj, "CalibrationDisk")
            self.renderer.target_camera(self.lightref, "LightRefCam")

            # Render blender scenes
            self.renderer.render(metainfo)

        self.logger.debug("Rendering completed")

    def save_results(self):
        """Save simulation results to a file."""
        self.logger.debug("Saving propagation results")

        print_list = []
        print_list.append([self.spacecraft.date_history, "date"])
        print_list.append([self.spacecraft.pos_history, "vector"])
        print_list.append([self.spacecraft.vel_history, "vector"])
        #print_list.append([self.spacecraft.rot_history,False])
        print_list.append([self.sssb.pos_history, "vector"])
        print_list.append([self.sssb.vel_history, "vector"])
        #print_list.append([self.sssb.rot_history,False])
        float_formatter = "{:.16f}".format
        np.set_printoptions(formatter={'float_kind': float_formatter})

        with open(str(self.res_dir / "DynamicsHistory.txt"), "w+") as file:

            for i in range(0, len(self.spacecraft.date_history)):
                line = ""
                sepr = "\t"
                for history in print_list:
                    if (history[1] == "date"):
                        value = history[0][i]
                    elif (history[1] == "vector"):
                        value = np.asarray(history[0][i].toArray())

                    line = line + str(value) + sepr

                line = line + "\n"
                file.write(line)

        self.logger.debug("Propagation results saved")