This function tries to fix critical events originating from the queue submission system.

        General strategy, first try to increase resources in order to fix the problem,
        if this is not possible, call a task specific method to attempt to decrease the demands.

        Returns:
            1 if task has been fixed else 0.

def fix_queue_critical(self):
        """
        This function tries to fix critical events originating from the queue submission system.

        General strategy, first try to increase resources in order to fix the problem,
        if this is not possible, call a task specific method to attempt to decrease the demands.

        Returns:
            1 if task has been fixed else 0.
        """
        from pymatgen.io.abinit.scheduler_error_parsers import NodeFailureError, MemoryCancelError, TimeCancelError
        #assert isinstance(self.manager, TaskManager)

        self.history.info('fixing queue critical')
        ret = "task.fix_queue_critical: "

        if not self.queue_errors:
            # TODO
            # paral_kgb = 1 leads to nasty sigegv that are seen as Qcritical errors!
            # Try to fallback to the conjugate gradient.
            #if self.uses_paral_kgb(1):
            #    logger.critical("QCRITICAL with PARAL_KGB==1. Will try CG!")
            #    self.set_vars(paral_kgb=0)
            #    self.reset_from_scratch()
            #    return
            # queue error but no errors detected, try to solve by increasing ncpus if the task scales
            # if resources are at maximum the task is definitively turned to errored
            if self.mem_scales or self.load_scales:
                try:
                    self.manager.increase_resources()  # acts either on the policy or on the qadapter
                    self.reset_from_scratch()
                    ret += "increased resources"
                    return ret
                except ManagerIncreaseError:
                    self.set_status(self.S_ERROR, msg='unknown queue error, could not increase resources any further')
                    raise FixQueueCriticalError
            else:
                self.set_status(self.S_ERROR, msg='unknown queue error, no options left')
                raise FixQueueCriticalError

        else:
            print("Fix_qcritical: received %d queue_errors" % len(self.queue_errors))
            print("type_list: %s" % list(type(qe) for qe in self.queue_errors))

            for error in self.queue_errors:
                self.history.info('fixing: %s' % str(error))
                ret += str(error)
                if isinstance(error, NodeFailureError):
                    # if the problematic node is known, exclude it
                    if error.nodes is not None:
                        try:
                            self.manager.exclude_nodes(error.nodes)
                            self.reset_from_scratch()
                            self.set_status(self.S_READY, msg='excluding nodes')
                        except:
                            raise FixQueueCriticalError
                    else:
                        self.set_status(self.S_ERROR, msg='Node error but no node identified.')
                        raise FixQueueCriticalError

                elif isinstance(error, MemoryCancelError):
                    # ask the qadapter to provide more resources, i.e. more cpu's so more total memory if the code
                    # scales this should fix the memeory problem
                    # increase both max and min ncpu of the autoparalel and rerun autoparalel
                    if self.mem_scales:
                        try:
                            self.manager.increase_ncpus()
                            self.reset_from_scratch()
                            self.set_status(self.S_READY, msg='increased ncps to solve memory problem')
                            return
                        except ManagerIncreaseError:
                            self.history.warning('increasing ncpus failed')

                    # if the max is reached, try to increase the memory per cpu:
                    try:
                        self.manager.increase_mem()
                        self.reset_from_scratch()
                        self.set_status(self.S_READY, msg='increased mem')
                        return
                    except ManagerIncreaseError:
                        self.history.warning('increasing mem failed')

                    # if this failed ask the task to provide a method to reduce the memory demand
                    try:
                        self.reduce_memory_demand()
                        self.reset_from_scratch()
                        self.set_status(self.S_READY, msg='decreased mem demand')
                        return
                    except DecreaseDemandsError:
                        self.history.warning('decreasing demands failed')

                    msg = ('Memory error detected but the memory could not be increased neither could the\n'
                           'memory demand be decreased. Unrecoverable error.')
                    self.set_status(self.S_ERROR, msg)
                    raise FixQueueCriticalError

                elif isinstance(error, TimeCancelError):
                    # ask the qadapter to provide more time
                    print('trying to increase time')
                    try:
                        self.manager.increase_time()
                        self.reset_from_scratch()
                        self.set_status(self.S_READY, msg='increased wall time')
                        return
                    except ManagerIncreaseError:
                        self.history.warning('increasing the waltime failed')

                    # if this fails ask the qadapter to increase the number of cpus
                    if self.load_scales:
                        try:
                            self.manager.increase_ncpus()
                            self.reset_from_scratch()
                            self.set_status(self.S_READY, msg='increased number of cpus')
                            return
                        except ManagerIncreaseError:
                            self.history.warning('increase ncpus to speed up the calculation to stay in the walltime failed')

                    # if this failed ask the task to provide a method to speed up the task
                    try:
                        self.speed_up()
                        self.reset_from_scratch()
                        self.set_status(self.S_READY, msg='task speedup')
                        return
                    except DecreaseDemandsError:
                        self.history.warning('decreasing demands failed')

                    msg = ('Time cancel error detected but the time could not be increased neither could\n'
                           'the time demand be decreased by speedup of increasing the number of cpus.\n'
                           'Unrecoverable error.')
                    self.set_status(self.S_ERROR, msg)

                else:
                    msg = 'No solution provided for error %s. Unrecoverable error.' % error.name
                    self.set_status(self.S_ERROR, msg)

        return 0