1 // =============================================================================
2 // PROJECT CHRONO - http://projectchrono.org
3 //
4 // Copyright (c) 2019 projectchrono.org
5 // All rights reserved.
6 //
7 // Use of this source code is governed by a BSD-style license that can be found
8 // in the LICENSE file at the top level of the distribution and at
9 // http://projectchrono.org/license-chrono.txt.
10 //
11 // =============================================================================
12 // Authors: Asher Elmquist
13 // =============================================================================
14 //
15 // Class for managing the Optix rendering system
16 //
17 // =============================================================================
18 
19 #include "chrono_sensor/ChSensorManager.h"
20 
21 #include "chrono_sensor/sensors/ChOptixSensor.h"
22 #include <iomanip>
23 #include <iostream>
24 
25 namespace chrono {
26 namespace sensor {
27 
ChSensorManager(ChSystem * chrono_system)28 CH_SENSOR_API ChSensorManager::ChSensorManager(ChSystem* chrono_system) : m_verbose(false), m_optix_reflections(9) {
29     // save the chrono system handle
30     m_system = chrono_system;
31     scene = chrono_types::make_shared<ChScene>();
32     m_device_list = {0};
33 }
34 
~ChSensorManager()35 CH_SENSOR_API ChSensorManager::~ChSensorManager() {}
36 
GetEngine(int context_id)37 CH_SENSOR_API std::shared_ptr<ChOptixEngine> ChSensorManager::GetEngine(int context_id) {
38     if (context_id < m_engines.size())
39         return m_engines[context_id];
40     std::cerr << "ERROR: index out of render group vector bounds\n";
41     return NULL;
42 }
43 
Update()44 CH_SENSOR_API void ChSensorManager::Update() {
45     // update the scene
46     // scene->PackFrame(m_system);
47     //
48     // have all the optix engines update their sensor
49     for (auto pEngine : m_engines) {
50         pEngine->UpdateSensors(scene);
51     }
52 
53     // have the sensormanager update all of the non-optix sensor (IMU and GPS).
54     // TODO: perhaps create a thread that takes care of this? Tradeoff since IMU should require some data from EVERY
55     // step
56     if (m_dynamics_manager)
57         m_dynamics_manager->UpdateSensors();
58 }
59 
SetDeviceList(std::vector<unsigned int> device_ids)60 CH_SENSOR_API void ChSensorManager::SetDeviceList(std::vector<unsigned int> device_ids) {
61     // set the list of devices to use
62     m_device_list = device_ids;
63 }
GetDeviceList()64 CH_SENSOR_API std::vector<unsigned int> ChSensorManager::GetDeviceList() {
65     // return the list of devices being used
66     return m_device_list;
67 }
68 
ReconstructScenes()69 CH_SENSOR_API void ChSensorManager::ReconstructScenes() {
70     for (auto eng : m_engines) {
71         eng->ConstructScene();
72     }
73 }
74 
SetMaxEngines(int num_groups)75 CH_SENSOR_API void ChSensorManager::SetMaxEngines(int num_groups) {
76     if (num_groups > 0 && num_groups < 1000) {
77         m_allowable_groups = num_groups;
78     }
79 }
80 
SetRayRecursions(int rec)81 CH_SENSOR_API void ChSensorManager::SetRayRecursions(int rec) {
82     if (rec >= 0)
83         m_optix_reflections = rec;
84 }
85 
AddSensor(std::shared_ptr<ChSensor> sensor)86 CH_SENSOR_API void ChSensorManager::AddSensor(std::shared_ptr<ChSensor> sensor) {
87     // check if sensor is already in sensor list
88     if (std::find(m_sensor_list.begin(), m_sensor_list.end(), sensor) != m_sensor_list.end()) {
89         std::cerr << "WARNING: Sensor already exists in manager. Ignoring this addition\n";
90         return;
91     }
92     m_sensor_list.push_back(sensor);
93 
94     if (auto pOptixSensor = std::dynamic_pointer_cast<ChOptixSensor>(sensor)) {
95         m_render_sensor.push_back(sensor);
96         //******** give each render group all sensor with same update rate *************//
97         bool found_group = false;
98 
99         // add the sensor to an engine with sensor of similar update frequencies
100         for (auto engine : m_engines) {
101             if (!found_group && engine->GetSensor().size() > 0 &&
102                 abs(engine->GetSensor()[0]->GetUpdateRate() - sensor->GetUpdateRate()) < 0.001) {
103                 found_group = true;
104                 engine->AssignSensor(pOptixSensor);
105                 if (m_verbose)
106                     std::cout << "Sensor added to existing engine\n";
107             }
108         }
109 
110         try {
111             // create new engines only when we need them
112             if (!found_group) {
113                 if (m_engines.size() < m_allowable_groups) {
114                     auto engine = chrono_types::make_shared<ChOptixEngine>(
115                         m_system, m_device_list[(int)m_engines.size()], m_optix_reflections,
116                         m_verbose);  // limits to 2 gpus, TODO: check if device supports cuda
117 
118                     // engine->ConstructScene();
119                     engine->AssignSensor(pOptixSensor);
120 
121                     m_engines.push_back(engine);
122                     if (m_verbose)
123                         std::cout << "Created another OptiX engine. Now at: " << m_engines.size() << "\n";
124 
125                 } else {  // if we are not allowed to create additional groups, warn the user and polute the first group
126                     // std::cout << "No more allowable groups, consider allowing more groups if performace would
127                     // increase\n";
128                     m_engines[0]->AssignSensor(pOptixSensor);
129                     if (m_verbose)
130                         std::cout << "Couldn't find suitable existing OptiX engine, so adding to first engine\n";
131                 }
132             }
133         }
134         catch (std::exception& e) {
135             std::cerr << "Failed to create a ChOptixEngine, with error:\n" << e.what() << "\n";
136             exit(1);
137         }
138     } else {
139         if (!m_dynamics_manager) {
140             m_dynamics_manager = chrono_types::make_shared<ChDynamicsManager>(m_system);
141         }
142 
143         // add pure dynamic sensor to dynamic manager
144         m_dynamics_manager->AssignSensor(sensor);
145     }
146 }
147 
148 }  // namespace sensor
149 }  // namespace chrono
150