Task: Fix ParmParse::query_enum_case_insensitive (AMReX-Codes/amrex#4144)

org: AMReX-Codes
repo: amrex
pr_number: 4144
issue_title: Fix ParmParse::query_enum_case_insensitive
issue_body: Since #4143, we can no longer cast the position of the found string in the vector of all names to obtain its enum value, because the enum values can now have duplicates.

resolved_issues: number: 4143
title: AMREX_ENUM: Add more capabilites
body: Add support for `=`. For example,

```c++
    AMREX_ENUM(MyColor,
               red,
               chi=red,
               green,
               blue,
               Default = green);
```
The underlying values are then
```c++
    { red = 0,
      chi = 0,
      green = 1,
      blue = 2,
      Default = 1}
```
We can then have
```c++
    assert(amrex::getEnum<MyColor2>("red") == MyColor2::red);
    assert(amrex::getEnum<MyColor2>("chi") == MyColor2::chi);
    assert(amrex::getEnum<MyColor2>("green") == MyColor2::green);
    assert(amrex::getEnum<MyColor2>("blue") == MyColor2::blue);
    assert(amrex::getEnum<MyColor2>("Default") == MyColor2::Default);
```
Because of there are duplicated values, using value to get name string will return the first matched string. Currently, I don't see a way to fix it. But, since `MyColor::red == MyColor::chi` is true, it's also not outrageously wrong.
```c++
    assert(amrex::getEnumNameString(MyColor2::red) == "red");
    assert(amrex::getEnumNameString(MyColor2::chi) == "red");
    assert(amrex::getEnumNameString(MyColor2::green) == "green");
    assert(amrex::getEnumNameString(MyColor2::blue) == "blue");
    assert(amrex::getEnumNameString(MyColor2::Default) == "green");
```
P.S. Chi means red in Chinese. https://en.wikipedia.org/wiki/Radical_155


Reference solution:
fix_patch: diff --git a/Src/Base/AMReX_Enum.H b/Src/Base/AMReX_Enum.H
index 2bb503d4113..b94e30d396e 100644
--- a/Src/Base/AMReX_Enum.H
+++ b/Src/Base/AMReX_Enum.H
@@ -67,6 +67,26 @@ namespace amrex
         }
     }
 
+    template <typename T, typename ET = amrex_enum_traits<T>,
+              std::enable_if_t<ET::value,int> = 0>
+    T getEnumCaseInsensitive (std::string_view const& s)
+    {
+        auto const& kv = getEnumNameValuePairs<T>();
+        std::string ls = amrex::toLower(std::string(s));
+        auto it = std::find_if(kv.begin(), kv.end(),
+                               [&] (auto const& x) -> bool
+                                   { return amrex::toLower(x.first) == ls; });
+        if (it != kv.end()) {
+            return it->second;
+        } else {
+            std::string error_msg("amrex::getEnumCaseInsensitive: Unknown enum: ");
+            error_msg.append(s).append(" in AMREX_ENUM(").append(ET::class_name)
+                .append(", ").append(ET::enum_names).append(").");
+            throw std::runtime_error(error_msg);
+            return T();
+        }
+    }
+
     template <typename T, typename ET = amrex_enum_traits<T>,
               std::enable_if_t<ET::value,int> = 0>
     std::string getEnumNameString (T const& v)
diff --git a/Src/Base/AMReX_ParmParse.H b/Src/Base/AMReX_ParmParse.H
index 63c0c45431a..42e62a05ab3 100644
--- a/Src/Base/AMReX_ParmParse.H
+++ b/Src/Base/AMReX_ParmParse.H
@@ -1329,19 +1329,14 @@ public:
         std::string s;
         int exist = this->query(name, s, ival);
         if (exist) {
-            s = amrex::toLower(s);
-            auto const& enum_names = amrex::getEnumNameStrings<T>();
-            auto found = std::find_if(enum_names.begin(), enum_names.end(),
-                                      [&] (std::string const& ename) {
-                                          return amrex::toLower(ename) == s;
-                                      });
-            if (found != enum_names.end()) {
-                ref = static_cast<T>(std::distance(enum_names.begin(), found));
-            } else {
-                std::string msg("query_enum_case_insensitive(\"");
-                msg.append(name).append("\",").append(amrex::getEnumClassName<T>())
-                    .append("&) failed.");
-                throw std::runtime_error(msg);
+            try {
+                ref = amrex::getEnumCaseInsensitive<T>(s);
+            } catch (...) {
+                if (amrex::Verbose() > 0) {
+                    amrex::Print() << "amrex::ParmParse::query_enum_case_insensitive (input name: "
+                                   << this->prefixedName(name) << "):\n";
+                }
+                throw;
             }
         }
         return exist;