void Device::init(std::vector<const char *> &layers,
                  std::vector<const char *> &extensions) {
    // request all queues
    const std::vector<VkQueueFamilyProperties> queue_props =
        phy_.queue_properties();
    std::vector<VkDeviceQueueCreateInfo> queue_info;
    queue_info.reserve(queue_props.size());

    std::vector<std::vector<float>> queue_priorities;

    for (uint32_t i = 0; i < (uint32_t)queue_props.size(); i++) {
        VkDeviceQueueCreateInfo qi = {};
        qi.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
        qi.pNext = NULL;
        qi.queueFamilyIndex = i;
        qi.queueCount = queue_props[i].queueCount;

        queue_priorities.emplace_back(qi.queueCount, 0.0f);

        qi.pQueuePriorities = queue_priorities[i].data();
        if (queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
            graphics_queue_node_index_ = i;
        }
        queue_info.push_back(qi);
    }

    VkDeviceCreateInfo dev_info = {};
    dev_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
    dev_info.pNext = NULL;
    dev_info.queueCreateInfoCount = queue_info.size();
    dev_info.pQueueCreateInfos = queue_info.data();
    dev_info.enabledLayerCount = layers.size();
    dev_info.ppEnabledLayerNames = layers.data();
    dev_info.enabledExtensionCount = extensions.size();
    dev_info.ppEnabledExtensionNames = extensions.data();

    // request all supportable features enabled
    auto features = phy().features();
    dev_info.pEnabledFeatures = &features;

    init(dev_info);
}
////////////////////////////////////////////////////////////////////////////////
// Simulation::init_terminals                                                 //
//                                                                            //
// initializes terminals for a new iteration                                  //
////////////////////////////////////////////////////////////////////////////////
void Simulation::init_terminals(){

	adapt_struct adapt (sim_par.get_TxMode(), sim_par.get_AdaptMode(),
			sim_par.get_TxPowerMax(), sim_par.get_TxPowerMin(),
			sim_par.get_TxPowerStepUp(),sim_par.get_TxPowerStepDown(),
			sim_par.get_TargetPER(),sim_par.get_LAMaxSucceedCounter(),
			sim_par.get_LAFailLimit(), sim_par.get_UseRxMode());

	mac_struct mac(sim_par.get_RetryLimit(), sim_par.get_RTSThreshold(),
			sim_par.get_FragmentationThresh(), sim_par.get_QueueSize(),
			sim_par.get_set_BA_agg());

	PHY_struct phy(sim_par.get_NoiseVariance(), sim_par.get_CCASensitivity());

	traffic_struct tr_dl(sim_par.get_DataRateDL(), sim_par.get_PacketLength(),
			sim_par.get_ArrivalTime());

	traffic_struct tr_ul(sim_par.get_DataRateUL(), sim_par.get_PacketLength(),
			sim_par.get_ArrivalTime());

	timestamp tr_time = sim_par.get_TransientTime();

	for (unsigned i = 0; i < sim_par.get_NumberAPs(); i++) {
		AccessPoint* ap = new AccessPoint(sim_par.get_APPosition(i), &main_sch, ch,
				&randgent, &log, mac, phy, tr_time);
		term_vector.push_back(ap);

		if (log(log_type::setup))
			log << *ap << " created at position " << sim_par.get_APPosition(i)
			<< '\n' << endl;
	}


	double cell_radius = sim_par.get_Radius();

	// Array containing the amount of connections belonging to each AC
	unsigned ppArray[5] = {round(2*sim_par.get_ppAC_BK()*sim_par.get_NumberStas()),
					  	   round(2*sim_par.get_ppAC_BE()*sim_par.get_NumberStas()),
						   round(2*sim_par.get_ppAC_VI()*sim_par.get_NumberStas()),
						   round(2*sim_par.get_ppAC_VO()*sim_par.get_NumberStas()),
						   round(2*sim_par.get_ppLegacy()*sim_par.get_NumberStas())};
	unsigned sum = 0;
	for(int k = 0; k < 5; k++) {
		sum = sum + ppArray[k];
	}
	int diff = sum - 2*sim_par.get_NumberStas();
	if(diff > 0) {
		for(int k = 0; k < 5; k++) {
			while(ppArray[k] > 0 && diff > 0){
				ppArray[k]--;
				diff--;
			}
		}
	}
	if(diff < 0)	{
		ppArray[0] = (-1)*diff;
	}
	vector<int> noZe_ppArray;
	accCat MS_AC = AC_BK;
	accCat AP_AC = AC_BK;
	int idx = 0;

	for (unsigned i = 0; i < sim_par.get_NumberStas(); i++) {

		// Vector containing elements of ppArray that are non-zero
		noZe_ppArray.clear();
		for(int k = 0; k < 5; k++) {
			if(ppArray[k] != 0) noZe_ppArray.push_back(k);
		}
		// Choose one access category randomly
		if(noZe_ppArray.size() != 0) {
			idx = randgent.from_vec(noZe_ppArray);
			MS_AC = allACs[idx];
			ppArray[idx]--;
		}

		// if just one mobile station, then distance = cell radius
		Position pos(cell_radius,0);
		// else Stas are uniformly distributed
		if (sim_par.get_NumberStas() > 1) {
			do {
				pos = Position (randgent.uniform(-cell_radius,cell_radius),
						randgent.uniform(-cell_radius,cell_radius));
			} while(pos.distance() > cell_radius);
		}

		MobileStation* ms = new MobileStation(pos, &main_sch, ch, &randgent,
				&log, mac, phy, tr_time);
		term_vector.push_back(ms);

		double min_dist = HUGE_VAL;
		int min_index = -1;
		for (unsigned count = 0; count < sim_par.get_NumberAPs(); count++) {
			double dist = pos.distance(sim_par.get_APPosition(count));
			if (dist < min_dist) {
				min_dist = dist;
				min_index = count;
			}
		}

		// Vector containing elements of ppArray that are non-zero
		noZe_ppArray.clear();
		for(int k = 0; k < 5; k++) {
			if(ppArray[k] != 0) noZe_ppArray.push_back(k);
		}
		// Choose one access category randomly
		if(noZe_ppArray.size() != 0) {
			idx = randgent.from_vec(noZe_ppArray);
			AP_AC = allACs[idx];
			ppArray[idx]--;
		}

		// Connect mobile terminal to closest AP
		connect_two(term_vector[min_index], AP_AC, ms, MS_AC, ch, adapt, tr_dl, tr_ul);

		if (log(log_type::setup))
			log << *ms << " created at position " << pos << " with distance "
			<< min_dist << " m to " << *term_vector[min_index]
		    << "\nMobile station AC: "<< MS_AC << ". Access Point AC: "
			<< AP_AC << "." <<endl;
	}


	if (log(log_type::setup)) log_connections();
}
VkFormatProperties Device::format_properties(VkFormat format) {
    VkFormatProperties data;
    vkGetPhysicalDeviceFormatProperties(phy().handle(), format, &data);

    return data;
}