Re. getting the key corresponding to the maximum value: I see a lot of complicated implementations of MaxBy when you can use one of the overloads of Aggregate to similar effect:
var keyForMaxP1 = dict.Keys.Aggregate((i, j) => dict[i].P1 >= dict[j].P1 ? i : j);
var keyForMaxP2 = dict.Keys.Aggregate((i, j) => dict[i].P2 >= dict[j].P2 ? i : j);
Edit: If you want to get multiple maximum keys, you'll need something like
var allMaxKeysForP1 = dict.Keys.Aggregate(
    new { Value = double.NegativeInfinity, Keys = new List<int>() },
    (a, k) =>
        {
            if (a.Value > dict[k].P1) return a;
            if (a.Value.Equals(dict[k].P1))
            {
                a.Keys.Add(k);
                return a;
            }
            return new { Value = dict[k].P1, Keys = new List<int> { k } };
        },
    a => a.Keys);
at which point you might want to consider implementing this as an AllMaxBy method.