public async Task <IActionResult> Otimizar([FromBody] ParametrosCenso _formulario)
        {
            this.Formulario = _formulario;

            Stopwatch sw = new Stopwatch();

            sw.Start();

            var TaskEnade = await Task.Run(() => {
                return(this.Context.CursoCenso.ToList());
            });

            var ResId = Convert.ToInt64(DateTime.Now.ToString("yyyyMMddHHmmss"));

            try
            {
                var query = await this.Context.ProfessorCursoEmec.ToListAsync();

                var query20p = await this.Context.ProfessorCursoEmec20p.ToListAsync();

                var ListaCursoArea = await this.CursoEnquadramentoContext.CursoEnquadramento.ToListAsync();

                var ListaPrevisaoSKU = GeraListaPrevisaoSKU();

                var Cursoprofessor = MontaCursoProfessor(query, ListaCursoArea);

                // // Obtem lista dos professores escolhidos no filtro
                var lista = _formulario.MontaLista();

                List <CursoProfessor> cursoProfessorAtual = new List <CursoProfessor>();
                Cursoprofessor.ForEach((item) => {
                    cursoProfessorAtual.Add((CursoProfessor)item.Clone());
                }
                                       );

                var CursoNota = getNotaCursos(query, ListaCursoArea);

                var CursoEnade = TaskEnade.Where(x => x.IndEnade.Contains('S')).Select(c => c.CodEmec.ToString()).Distinct().ToList();

                List <Resultado> ResultadoAtual = Otm.CalculaNotaCursos(ListaPrevisaoSKU, cursoProfessorAtual, CursoEnade);

                // ######################## Alavanca 20% ######################## //

                if (_formulario.otimiza20p)
                {
                    Otm.AddProfessor20p(Cursoprofessor, query20p, ListaPrevisaoSKU, _formulario, CursoEnade);
                }

                List <Resultado> resultado = Otm.OtimizaCurso(ListaPrevisaoSKU, query, Cursoprofessor, ListaCursoArea, _formulario);

                // ############## Monta resultados a partir do cenário otimizado ################# //

                var Resumoresultado = Otm.MontaResultadoFinal(resultado);

                var ResumoresultadoAtual = Otm.MontaResultadoFinal(ResultadoAtual);


                sw.Stop();

                // ############ Monta Objeto resultado Otimizado ############## //
                Task <string> json = Task.Run(
                    () => {
                    return(JsonConvert.SerializeObject(resultado));
                }
                    );

                Task <string> formJson = Task.Run(
                    () => {
                    return(JsonConvert.SerializeObject(_formulario));
                }
                    );

                Task <string> resumoJson = Task.Run(
                    () => {
                    return((string)JsonConvert.SerializeObject(Resumoresultado));
                }
                    );

                Task <string> professorJson = Task.Run(
                    () => {
                    return(JsonConvert.SerializeObject(Cursoprofessor));
                }
                    );


                // ############ Monta Objeto resultado Atual ############## //
                Task <string> jsonAt = Task.Run(
                    () => {
                    return(JsonConvert.SerializeObject(ResultadoAtual));
                }
                    );

                Task <string> formJsonAt = Task.Run(
                    () => {
                    return(JsonConvert.SerializeObject(_formulario));
                }
                    );

                Task <string> resumoJsonAt = Task.Run(
                    () => {
                    return((string)JsonConvert.SerializeObject(ResumoresultadoAtual));
                }
                    );

                Task <string> professorJsonAt = Task.Run(
                    () => {
                    return(JsonConvert.SerializeObject(cursoProfessorAtual));
                }
                    );

                var objRes = new TbResultado();
                objRes.Id = ResId;

                var objResAtual = new TbResultadoAtual();
                objResAtual.Id = ResId;


                Task.WaitAll(json, formJson, resumoJson, professorJson);
                Task.WaitAll(jsonAt, formJsonAt, resumoJsonAt, professorJsonAt);

                objRes.Resultado     = json.Result;
                objRes.Parametro     = formJson.Result;
                objRes.Resumo        = resumoJson.Result;
                objRes.Professores   = professorJson.Result;
                objRes.TempoExecucao = DateTime.Now.ToString("HH:mm:ss");
                objRes.Observacao    = _formulario.Observacao;

                objResAtual.Resultado   = jsonAt.Result;
                objResAtual.Parametro   = formJsonAt.Result;
                objResAtual.Resumo      = resumoJsonAt.Result;
                objResAtual.Professores = professorJsonAt.Result;

                ProducaoContext.Add(objRes);
                ProducaoContext.Add(objResAtual);

                ProducaoContext.SaveChanges();

                return(Ok());
            }
            catch (System.Exception e)
            {
                return(StatusCode(StatusCodes.Status500InternalServerError, "Erro no processamento." + e.Message));
            }
        }
        //#################### Gera notas para cursos #####################
        private dynamic getNotaCursos(List <ProfessorCursoEmec> _query, List <CursoEnquadramento> _cursoProfessor)
        {
            try {
                var query = _query;

                var ListaPrevisaoSKU = GeraListaPrevisaoSKU();


                List <CursoProfessor> cursoProfessor;

                // ########## Monta a lista de cursos por professores ##########
                cursoProfessor = MontaCursoProfessor(query, _cursoProfessor);
                var           cctx    = this.Context.CursoCenso.ToList();
                List <double> percent = new List <double>();
                //conte

                // ######## Calcula Nota Prévia dos Cursos ###########

                foreach (var item in cursoProfessor)
                {
                    double qtdProf = item.Professores
                                     .Count();
                    double qtdD = item.Professores.Where(x => x.Titulacao == "DOUTOR")
                                  .Count();
                    double qtdM = item.Professores.Where(x => x.Titulacao == "MESTRE" | x.Titulacao == "DOUTOR")
                                  .Count();
                    double qtdR = item.Professores.Where(x => x.Regime == "TEMPO INTEGRAL" | x.Regime == "TEMPO PARCIAL")
                                  .Count();

                    double perc_D = qtdD / qtdProf;
                    double perc_M = qtdM / qtdProf;
                    double perc_R = qtdR / qtdProf;

                    var ii = cctx.FirstOrDefault(x => x.CodEmec == item.CodEmec);

                    if (ii != null)
                    {
                        percent.Add(perc_D);
                        var area = ii.CodArea;
                        //##### Previsão Doutor


                        if (ListaPrevisaoSKU.ContainsKey(area))
                        {
                            var prev = ListaPrevisaoSKU[area];

                            var prev_minM = prev.P_Min_Mestre;
                            var prev_maxM = prev.P_Max_Mestre;

                            var prev_minD = prev.P_Min_Doutor;
                            var prev_maxD = prev.P_Max_Doutor;

                            var prev_minR = prev.P_Min_Regime;
                            var prev_maxR = prev.P_Max_Regime;

                            var M = Otm.N_Escala(prev_minM, prev_maxM, perc_M);
                            var D = Otm.N_Escala(prev_minD, prev_maxD, perc_D);
                            var R = Otm.N_Escala(prev_minR, prev_maxR, perc_R);

                            double notaM = (M == null) ? 0 : Convert.ToDouble(M);
                            double notaD = (D == null) ? 0 : Convert.ToDouble(D);
                            double notaR = (R == null) ? 0 : Convert.ToDouble(R);

                            item.Nota_Mestre = notaM;
                            item.Nota_Doutor = notaD;
                            item.Nota_Regime = notaR;
                        }
                    }
                }


                var result = cursoProfessor
                             .Select(x => new
                {
                    x.CodEmec,
                    x.Nota_Mestre,
                    x.Nota_Doutor,
                    x.Nota_Regime,
                    Mestres = x.Professores
                              .Where(p => p.Titulacao == "MESTRE" || p.Titulacao == "DOUTOR")
                              .Count(),
                    QtdProfessores = x.Professores.Count(),
                    doutores       = x.Professores
                                     .Where(p => p.Titulacao == "DOUTOR").Count(),
                    cctx.FirstOrDefault(c => c.CodEmec == x.CodEmec).CodArea,
                    cctx.FirstOrDefault(c => c.CodEmec == x.CodEmec).NomCursoCenso,
                })
                             .ToList();

                return(result);
            }
            catch (Exception ex) {
                return(null);
            }
        }