TEST_F(UnitsFixture,IddUnits_DefaultValue) {
  IdfObject idfObject(IddObjectType::OS_Building);
  // IdfObject::getQuantity(unsigned index, bool returnDefault=false, bool returnIP=false) const;

  // this field is empty but has a default value of 3 m
  EXPECT_TRUE(idfObject.getQuantity(OS_BuildingFields::NominalFloortoFloorHeight, false).empty());

  OSOptionalQuantity siQ = idfObject.getQuantity(OS_BuildingFields::NominalFloortoFloorHeight, true, false);
  ASSERT_FALSE(siQ.empty());
  OptionalUnit mUnit = createUnit("m");
  ASSERT_TRUE(mUnit);
  EXPECT_EQ(*mUnit, siQ.get().units());
  EXPECT_EQ(3.0, siQ.get().value());

  OSOptionalQuantity ipQ = idfObject.getQuantity(OS_BuildingFields::NominalFloortoFloorHeight, true, true);
  ASSERT_FALSE(ipQ.empty());
  OptionalUnit ftUnit = createUnit("ft");
  ASSERT_TRUE(ftUnit);
  EXPECT_EQ(*ftUnit, ipQ.get().units());
  EXPECT_NE(3.0, ipQ.get().value());
  
  OptionalQuantity q = QuantityConverter::instance().convert(ipQ.get(), *mUnit);
  ASSERT_TRUE(q);
  EXPECT_DOUBLE_EQ(3.0, q->value());
}
boost::optional<Quantity> QuantityConverterSingleton::convert(const Quantity &original,
                                                              const Unit& targetUnits) const
{
  Quantity working(original);
  OptionalQuantity candidate;

  // See if nothing to be done. (Check for equality of system and base units + exponents.)
  if ((working.system() == targetUnits.system()) && (working.units() == targetUnits))
  {
    // Assume targetUnits has desired scale.
    working.setScale(targetUnits.scale().exponent);
    return working;
  }

  // All conversions go through SI
  if (working.system() != UnitSystem::SI) {
    candidate = m_convertToSI(working);
    if (!candidate) {
      return boost::none;
    }
    working = *candidate;
  }

  // Retain pretty string
  OptionalQuantity result = m_convertToTargetFromSI(working,targetUnits);
  if (result && 
      result->prettyUnitsString(false).empty() && 
      !targetUnits.prettyString(false).empty()) 
  {
    result->setPrettyUnitsString(targetUnits.prettyString(false));
  }

  return result;
}
TEST_F(UnitsFixture,QuantityConverter_PowerDensity) {
    Quantity siLpd(10.0,createSIPowerDensity());
    Unit ipPowerDensity = createUnit("W/ft^2").get();
    OptionalQuantity ipLpd = convert(siLpd,ipPowerDensity);
    Quantity siArea(1.0,pow(createSILength(),2));
    OptionalQuantity ipArea = convert(siArea,UnitSystem(UnitSystem::IP));
    ASSERT_TRUE(ipLpd);
    ASSERT_TRUE(ipArea);
    EXPECT_NEAR(10.0/ipArea->value(),ipLpd->value(),tol);
    EXPECT_EQ("W/ft^2",ipLpd->prettyUnitsString());
}
TEST_F(UnitsFixture,QuantityConverter_CFMandSIUsingSystem)
{
    LOG(Debug, "QuantityConverter_CFMandSIUsingSystem");

    SIUnit siu1(openstudio::SIExpnt(1));
    Quantity oneKg(1.0, siu1);
    OptionalQuantity intermediate = QuantityConverter::instance().convert(oneKg, UnitSystem(UnitSystem::CFM));
    ASSERT_TRUE(intermediate);
    OptionalQuantity copyOfCopy = QuantityConverter::instance().convert(*intermediate, UnitSystem(UnitSystem::SI));
    ASSERT_TRUE(copyOfCopy);
    EXPECT_NEAR(oneKg.value(),copyOfCopy->value(),tol);
    EXPECT_EQ(oneKg.standardUnitsString(false),copyOfCopy->standardUnitsString(false));
}
OSQuantityVector convert(const OSQuantityVector& original, const Unit& targetUnits) {
  OSQuantityVector result;
  Quantity testQuantity(0.0,original.units());
  OptionalQuantity offset = convert(testQuantity,targetUnits);
  if (!offset) {
    return result;
  }
  testQuantity.setValue(1.0);
  OptionalQuantity factorPlusOffset = convert(testQuantity,targetUnits);
  OS_ASSERT(factorPlusOffset);
  OS_ASSERT(offset->units() == factorPlusOffset->units());
  result = OSQuantityVector(offset->units(),original.values());
  result = result * (factorPlusOffset->value() - offset->value()) + offset.get();
  return result;
}
TEST_F(IdfFixture, IdfObject_GetQuantity)
{
    std::string text = "Building,                !- Building \n\
                      Building,                !- Name \n\
                      30.,                     !- North Axis {deg} \n\
                      City,                    !- Terrain \n\
                      0.04,                    !- Loads Convergence Tolerance Value \n\
                      0.4,                     !- Temperature Convergence Tolerance Value {deltaC} \n\
                      FullExterior,            !- Solar Distribution \n\
                      25;                      !- Maximum Number of Warmup Days";

  // make an idf object
  OptionalIdfObject oObj = IdfObject::load(text);
  ASSERT_TRUE(oObj);

  // Test get.
  OSOptionalQuantity ooq = oObj->getQuantity (4);
  ASSERT_TRUE(ooq.isSet());
  Quantity q = ooq.get();
  EXPECT_TRUE(q.value() == 0.4);
  EXPECT_TRUE(q.system() == UnitSystem::SI);
  EXPECT_TRUE(q.standardUnitsString() == "K");

  // Test set.
  OptionalQuantity oq = convert(q,UnitSystem(UnitSystem::IP));
  ASSERT_TRUE(oq);
  EXPECT_TRUE(oq->system() == UnitSystem::IP);
  EXPECT_DOUBLE_EQ(0.72,oq->value());
  oq->setValue(1.5);

  EXPECT_TRUE(oObj->setQuantity(4, *oq));
  ooq = oObj->getQuantity(4);
  ASSERT_TRUE(ooq.isSet());
  q = ooq.get();
  EXPECT_DOUBLE_EQ(0.83333333333333333,q.value());
  EXPECT_TRUE(q.system() == UnitSystem::SI);
  EXPECT_TRUE(q.standardUnitsString() == "K");
}
double SchedulesTabController::defaultStartingValue(const model::ScheduleDay& scheduleDay) {
  double result(0.3);
  if (model::OptionalScheduleTypeLimits typeLimits = scheduleDay.scheduleTypeLimits()) {
    OptionalUnit siU = model::ScheduleTypeLimits::units(typeLimits->unitType(),false);
    if (siU) {
      std::string unitType = typeLimits->unitType();
      boost::to_lower(unitType);
      char firstLetter = unitType[0];
      OptionalQuantity siQ;
      switch (firstLetter) {
      case 'a' :
        { 
          if (unitType == "activitylevel") {          
            siQ = Quantity(100.0,*siU);
          }
          else if (unitType == "angle") {
            siQ = Quantity(0.0,*siU);
          }
          else if (unitType == "availability") {
            siQ = Quantity(1.0,*siU);
          }
          break;
        }
      case 'c' :
        {
          if (unitType == "capacity") {
            siQ = Quantity(100.0,*siU);
          }
          else if (unitType == "clothinginsulation") {
            siQ = Quantity(0.5,*siU);
          }
          else if (unitType == "controlmode") {
            siQ = Quantity(0.0,*siU);
          }
          else if (unitType == "convectioncoefficient") {
            siQ = Quantity(10.0,*siU);
          }
          break;
        }
      case 'd' :
        {
          if (unitType == "deltatemperature") {
            siQ = Quantity(3.0,*siU);
          }
          break;
        }
      case 'm' :
        {
          if (unitType == "massflowrate") {
            siQ = Quantity(1.0,*siU);
          }
          break;
        }
      case 'p' :
        {
          if (unitType == "percent") {
            siQ = Quantity(50.0,*siU);
          }
          else if (unitType == "power") {
            siQ = Quantity(100.0,*siU);
          }
          else if (unitType == "precipitationrate") {
            siQ = Quantity(0.01,*siU);
          }
          else if (unitType == "pressure") {
            siQ = Quantity(100.0,*siU);
          }
          break;
        }
      case 'r' :
        {
          siQ = Quantity(1500.0,*siU);
          break;
        }
      case 's' :
        {
          if (unitType == "solarenergy") {
            siQ = Quantity(1000.0,*siU);
          }
          break;
        }
      case 't' :
        {
          if (unitType == "temperature") {
            siQ = Quantity(23.5,*siU);
          }
          break;
        }
      case 'v' :
        {
          if (unitType == "velocity") {
            siQ = Quantity(1.0,*siU);
          }
          if (unitType == "volumetricflowrate") {
            siQ = Quantity(1.0E-4,*siU);
          }
          break;
        }
      default :
        break;
      } // switch
      if (siQ) {
        result = siQ->value();
      }
    } // if siU
  }
  return result;
}
TEST_F(ModelFixture, PlanarSurface_FilmResistanceConversions)
{
  Quantity q;
  OptionalQuantity qc;

  q = createQuantity(0.61,"ft^2*R*h/Btu").get();
  qc = QuantityConverter::instance().convert(q,UnitSystem(UnitSystem::SI));
  ASSERT_TRUE(qc);
  EXPECT_EQ("s^3*K/kg",qc->standardUnitsString());
  EXPECT_NEAR(qc->value(),PlanarSurface::filmResistance(FilmResistanceType::StillAir_HorizontalSurface_HeatFlowsUpward),1.0E-8);

  q = createQuantity(0.62,"ft^2*R*h/Btu").get();
  qc = QuantityConverter::instance().convert(q,UnitSystem(UnitSystem::SI));
  ASSERT_TRUE(qc);
  EXPECT_EQ("s^3*K/kg",qc->standardUnitsString());
  EXPECT_NEAR(qc->value(),PlanarSurface::filmResistance(FilmResistanceType::StillAir_45DegreeSurface_HeatFlowsUpward),1.0E-8);

  q = createQuantity(0.68,"ft^2*R*h/Btu").get();
  qc = QuantityConverter::instance().convert(q,UnitSystem(UnitSystem::SI));
  ASSERT_TRUE(qc);
  EXPECT_EQ("s^3*K/kg",qc->standardUnitsString());
  EXPECT_NEAR(qc->value(),PlanarSurface::filmResistance(FilmResistanceType::StillAir_VerticalSurface),1.0E-8);

  q = createQuantity(0.76,"ft^2*R*h/Btu").get();
  qc = QuantityConverter::instance().convert(q,UnitSystem(UnitSystem::SI));
  ASSERT_TRUE(qc);
  EXPECT_EQ("s^3*K/kg",qc->standardUnitsString());
  EXPECT_NEAR(qc->value(),PlanarSurface::filmResistance(FilmResistanceType::StillAir_45DegreeSurface_HeatFlowsDownward),1.0E-8);

  q = createQuantity(0.92,"ft^2*R*h/Btu").get();
  qc = QuantityConverter::instance().convert(q,UnitSystem(UnitSystem::SI));
  ASSERT_TRUE(qc);
  EXPECT_EQ("s^3*K/kg",qc->standardUnitsString());
  EXPECT_NEAR(qc->value(),PlanarSurface::filmResistance(FilmResistanceType::StillAir_HorizontalSurface_HeatFlowsDownward),1.0E-8);

  q = createQuantity(0.17,"ft^2*R*h/Btu").get();
  qc = QuantityConverter::instance().convert(q,UnitSystem(UnitSystem::SI));
  ASSERT_TRUE(qc);
  EXPECT_EQ("s^3*K/kg",qc->standardUnitsString());
  EXPECT_NEAR(qc->value(),PlanarSurface::filmResistance(FilmResistanceType::MovingAir_15mph),1.0E-8);

  q = createQuantity(0.25,"ft^2*R*h/Btu").get();
  qc = QuantityConverter::instance().convert(q,UnitSystem(UnitSystem::SI));
  ASSERT_TRUE(qc);
  EXPECT_EQ("s^3*K/kg",qc->standardUnitsString());
  EXPECT_NEAR(qc->value(),PlanarSurface::filmResistance(FilmResistanceType::MovingAir_7p5mph),1.0E-8);
}
TEST_F(UnitsFixture, QuantityConverter_IPandSIUsingSystem)
{
    LOG(Debug, "QuantityConvert_ConvertUsingSystem");
    UnitSystem siSys(UnitSystem::SI);
    UnitSystem ipSys(UnitSystem::IP);

    IPUnit ipu1(openstudio::IPExpnt(0,1));
    Quantity ipq1(110.0, ipu1);
    OptionalQuantity siq1 = QuantityConverter::instance().convert(ipq1, siSys);
    EXPECT_TRUE(siq1);
    if (siq1) {
        SCOPED_TRACE("ipu1 to SI");
        testNumbersEqual(33.528,siq1->value());
        testStreamOutput("33.5 m", *siq1, 1);
    }

    IPUnit ftSquared(openstudio::IPExpnt(0,2));
    Quantity ipqFtSquared( 100.0, ftSquared );
    OptionalQuantity siqMSquared = QuantityConverter::instance().convert(ipqFtSquared, siSys);
    EXPECT_TRUE(siqMSquared);
    if (siqMSquared) {
        SCOPED_TRACE("ipqFtSquared to SI");
        testNumbersEqual(9.290304, siqMSquared->value());
        testStreamOutput("9.29 m^2", *siqMSquared, 2);
    }

    IPUnit ipu2(openstudio::IPExpnt(0,0,0,0,0,0,0,1));
    Quantity ipq2( 130.0, ipu2 );
    OptionalQuantity siq2 = QuantityConverter::instance().convert(ipq2, siSys);
    EXPECT_TRUE(siq2);
    if (siq2) {
        SCOPED_TRACE("ipu2 to SI");
        testNumbersEqual(578.268809984, siq2->value());
        testStreamOutput("578.3 N", *siq2, 1);
    }

    IPUnit ipu3(openstudio::IPExpnt(0,0,0,1));
    Quantity ipq3( 529.67, ipu3 );
    OptionalQuantity siq3 = QuantityConverter::instance().convert(ipq3, siSys);
    EXPECT_TRUE(siq3);
    if (siq3) {
        SCOPED_TRACE("ipu3 to SI");
        testNumbersEqual(294.261111111, siq3->value());
        testStreamOutput("294 K", *siq3, 0);
    }

    SIUnit siu4(openstudio::SIExpnt(1,2,-2));
    Quantity siq4( 1300.0, siu4 );
    OptionalQuantity ipq4 = QuantityConverter::instance().convert(siq4, ipSys);
    EXPECT_TRUE(ipq4);
    if (ipq4) {
        SCOPED_TRACE("siu4 to IP");
        testNumbersEqual(30849.4685255, ipq4->value());
        testStreamOutput("30849.47 lb_m*ft^2/s^2", *ipq4, 2);
    }

    SIUnit siu5(openstudio::SIExpnt(0,0,0,1));
    Quantity siq5( 294.0, siu5 );
    OptionalQuantity ipq5 = QuantityConverter::instance().convert(siq5, ipSys);
    EXPECT_TRUE(ipq5);
    if (ipq5) {
        SCOPED_TRACE("siu5 to IP");
        testNumbersEqual(529.2, ipq5->value());
        testStreamOutput("529.2 R", *ipq5, 1);
    }
}
TEST_F(UnitsFixture,QuantityConverter_OSQuantityVector) {
    // basic conversion
    OSQuantityVector testVec(createIPEnergy(),2u,100.0);
    Quantity testQ(100.0,createIPEnergy());

    OSQuantityVector resultVec = convert(testVec,UnitSystem(UnitSystem::Wh));
    OptionalQuantity resultQ = convert(testQ,UnitSystem(UnitSystem::Wh));
    ASSERT_EQ(2u,resultVec.size());
    ASSERT_TRUE(resultQ);
    EXPECT_EQ(resultQ.get(),resultVec.getQuantity(0));
    EXPECT_EQ(resultQ.get(),resultVec.getQuantity(1));
    EXPECT_EQ(resultQ->system(),resultVec.system());

    resultVec = convert(testVec,resultQ->units());
    resultQ = convert(testQ,resultQ->units());
    ASSERT_EQ(2u,resultVec.size());
    ASSERT_TRUE(resultQ);
    EXPECT_EQ(resultQ.get(),resultVec.getQuantity(0));
    EXPECT_EQ(resultQ.get(),resultVec.getQuantity(1));
    EXPECT_EQ(resultQ->system(),resultVec.system());

    // temperature conversion
    testVec = OSQuantityVector(createCelsiusTemperature(),2u,20.0);
    testQ = Quantity(20.0,createCelsiusTemperature());
    resultVec = convert(testVec,UnitSystem(UnitSystem::Fahrenheit));
    resultQ = convert(testQ,UnitSystem(UnitSystem::Fahrenheit));
    ASSERT_EQ(2u,resultVec.size());
    ASSERT_TRUE(resultQ);
    EXPECT_EQ(resultQ.get().units(),resultVec.units());
    // not sure why these aren't quite getting the precision we would like
    EXPECT_NEAR(resultQ.get().value(),resultVec.getQuantity(0).value(),1.0E-12);
    EXPECT_NEAR(resultQ.get().value(),resultVec.getQuantity(1).value(),1.0E-12);
    EXPECT_EQ(resultQ->system(),resultVec.system());
    EXPECT_TRUE(resultVec.isAbsolute());
    EXPECT_TRUE(resultQ->isAbsolute());

    testVec.setAsRelative();
    testQ.setAsRelative();
    resultVec = convert(testVec,UnitSystem(UnitSystem::Fahrenheit));
    resultQ = convert(testQ,UnitSystem(UnitSystem::Fahrenheit));
    ASSERT_EQ(2u,resultVec.size());
    ASSERT_TRUE(resultQ);
    EXPECT_EQ(resultQ.get().units(),resultVec.units());
    // not sure why these aren't quite getting the precision we would like
    EXPECT_NEAR(resultQ.get().value(),resultVec.getQuantity(0).value(),1.0E-12);
    EXPECT_NEAR(resultQ.get().value(),resultVec.getQuantity(1).value(),1.0E-12);
    EXPECT_EQ(resultQ->system(),resultVec.system());
    EXPECT_TRUE(resultVec.isRelative());
    EXPECT_TRUE(resultQ->isRelative());
}
TEST_F(UnitsFixture,QuantityConverter_BTUandIPUsingSystem)
{
    LOG(Debug, "QuantityConverter_BTUandIPUsingSystem");

    UnitSystem siSys(UnitSystem::SI);
    UnitSystem ipSys(UnitSystem::IP);
    UnitSystem btuSys(UnitSystem::BTU);

    // uses BTU to SI, SI to IP
    BTUUnit btuu1(openstudio::BTUExpnt(1,-2,0,0), 3);
    Quantity bQ( 67.5, btuu1 );
    testStreamOutput("67.5 kBtu/ft^2",bQ);
    OptionalQuantity ipQ = QuantityConverter::instance().convert( bQ, ipSys);
    EXPECT_TRUE(ipQ);
    if (ipQ) {
        EXPECT_EQ("lb_m/s^2",ipQ->standardUnitsString(false));
        EXPECT_EQ("klb_m/s^2",ipQ->standardUnitsString());
        SCOPED_TRACE("btu1 to IP");
        testNumbersEqual(1689985.20448, ipQ->value());
    }

    BTUUnit btuu2(openstudio::BTUExpnt(0,0,-1));
    bQ = Quantity(5000.0, btuu2);
    ipQ = QuantityConverter::instance().convert( bQ, ipSys);
    EXPECT_TRUE(ipQ);
    if (ipQ) {
        SCOPED_TRACE("bQ to IP, 1");
        testStreamOutput("1.3889 1/s",*ipQ,4);
    }

    bQ *= bQ; // 25E6/h^2
    ipQ = QuantityConverter::instance().convert( bQ, ipSys);
    EXPECT_TRUE(ipQ);
    if (ipQ) {
        SCOPED_TRACE("bQ to IP, 2");
        testStreamOutput("1.9290 1/s^2",*ipQ,4);
    }

    BTUUnit btuu3(openstudio::BTUExpnt(-1),-3);
    bQ = Quantity(1.0, btuu3);
    testStreamOutput("1 1/kBtu",bQ);
    OptionalQuantity siQ = QuantityConverter::instance().convert(bQ,siSys);
    EXPECT_TRUE(siQ);
    if (siQ) {
        EXPECT_EQ("1/J",siQ->prettyUnitsString(false));
        SCOPED_TRACE("btu3 to SI");
        testNumbersEqual(9.478171203133172e-4,siQ->value());
        siQ->setScale(0);
        SCOPED_TRACE("rescaled btu3 to SI");
        testNumbersEqual(9.478171203133172e-7,siQ->value());
    }

    // uses IP to SI, SI to BTU
    IPUnit ipu1(openstudio::IPExpnt(0,1,0,-1,0,0,0,1), -2);
    Quantity ipQ2( 2.0, ipu1);
    OptionalQuantity bQ2 = QuantityConverter::instance().convert( ipQ2, btuSys);
    EXPECT_TRUE(bQ2);
    if (bQ2) {
        EXPECT_EQ("Btu/R", bQ2->standardUnitsString(false));
        EXPECT_EQ("cBtu/R", bQ2->standardUnitsString());
        SCOPED_TRACE("ipu1 to BTU");
        testNumbersEqual(0.002570134927, bQ2->value(),1.0e-5);
        bQ2->setScale(0);
        EXPECT_EQ("Btu/R", bQ2->standardUnitsString());
        testNumbersEqual(2.570134927e-5, bQ2->value(),1.0e-5);
    }
}
TEST_F(IddFixture,IddFactory_Units) {
    std::vector<boost::regex> unsupported;
    unsupported.push_back(boost::regex("\\$"));
    unsupported.push_back(boost::regex("eV"));
    unsupported.push_back(boost::regex("hh:mm"));
    unsupported.push_back(boost::regex("percent"));
    unsupported.push_back(boost::regex("ppm"));

    IddObjectVector objects = IddFactory::instance().getObjects(IddFileType(IddFileType::WholeFactory));
    StringSet goodUnits;
    StringSet badUnits;
    for (const IddObject& object : objects) {
        IddFieldVector fields = object.nonextensibleFields();
        IddFieldVector temp = object.extensibleGroup();
        fields.insert(fields.end(),temp.begin(),temp.end());
        for (const IddField& field : fields) {
            OptionalString iddUnits = field.properties().units;
            OptionalUnit siUnit;
            if (iddUnits) {

                // check if already tested units
                if (goodUnits.find(*iddUnits) != goodUnits.end()) {
                    continue;
                }
                if (badUnits.find(*iddUnits) != badUnits.end()) {
                    continue;
                }

                // screen for unsupported units
                for (const boost::regex& re : unsupported) {
                    if (boost::regex_search(*iddUnits,re)) {
                        iddUnits = boost::none;
                        break;
                    }
                }
                if (!iddUnits) {
                    continue;
                }

                siUnit = field.getUnits(false);
                EXPECT_TRUE(siUnit || field.unitsBasedOnOtherField()) << object.name() << " field: " << field.name();
                if (siUnit) {
                    // could just return junk unit. if not junk, quantity will be convertible
                    // to UnitSystem::SI.
                    Quantity q(1.0,*siUnit);
                    OptionalQuantity testQ = convert(q,UnitSystem(UnitSystem::SI));
                    EXPECT_TRUE(testQ) << "Unable to convert unit '" << *iddUnits << "' to SI for field '"
                                       << field.name() << "' in IddObject '" << object.name() << "'.";
                    if (testQ) {
                        goodUnits.insert(*iddUnits);
                        EXPECT_TRUE(testQ->system() == UnitSystem::SI);
                    } else {
                        badUnits.insert(*iddUnits);
                        LOG(Debug,"Unable to convert unit '" << *iddUnits << "' to SI for field '"
                            << field.name() << "' in IddObject '" << object.name() << "'.");
                    }
                }
                else if (field.unitsBasedOnOtherField()) {
                    goodUnits.insert(*iddUnits);
                    continue;
                }
                else {
                    badUnits.insert(*iddUnits);
                    LOG(Debug,"Unable to instantiate unit '" << *iddUnits << "' for field '"
                        << field.name() << "' in IddObject '" << object.name() << "'.");
                    continue;
                }
                OptionalUnit ipUnit = field.getUnits(true);
                EXPECT_TRUE(ipUnit);
                if (ipUnit) {
                    // could just return junk unit. if not junk, quantity will be convertable
                    // to *siUnit or UnitSystem::SI.
                    Quantity q(1.0,*ipUnit);
                    OptionalQuantity testQ;
                    if (siUnit) {
                        testQ = convert(q,*siUnit);
                    }
                    else {
                        testQ = convert(q,UnitSystem(UnitSystem::SI));
                    }
                    EXPECT_TRUE(testQ);
                    if (testQ) {
                        goodUnits.insert(*iddUnits);
                    }
                    else {
                        badUnits.insert(ipUnit->standardString());
                        LOG(Debug,"Unable to convert unit " << *ipUnit << " to IDD/SI units " << *siUnit
                            << " for field '" << field.name() << "' in IddObject '" << object.name() << "'.");
                    }
                }
                else {
                    badUnits.insert(*iddUnits);
                    LOG(Debug,"Unable to instantiate ipUnit for field " << field.name() << " in IddObject "
                        << object.name() << ", which has units " << *siUnit << ".");
                }
            }
        }
    }
    LOG(Info,"IddUnitStrings not handled properly by the Factories and Converter:");
    for (const std::string& str : badUnits) {
        LOG(Info,"  " << str);
    }
    LOG(Info,"IddUnitStrings handled properly by the Factories and Converter:");
    for (const std::string& str : goodUnits) {
        LOG(Info,"  " << str);
    }
}