Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-29 08:24:13

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #include <boost/test/unit_test.hpp>
0010 
0011 #include "Acts/Material/BinnedSurfaceMaterial.hpp"
0012 #include "Acts/Material/GridSurfaceMaterial.hpp"
0013 #include "Acts/Material/HomogeneousSurfaceMaterial.hpp"
0014 #include "Acts/Material/Material.hpp"
0015 #include "Acts/Material/MaterialSlab.hpp"
0016 #include "Acts/Material/MergedMaterialMarker.hpp"
0017 #include "Acts/Material/ProtoSurfaceMaterial.hpp"
0018 #include "Acts/Utilities/AxisDefinitions.hpp"
0019 #include "Acts/Utilities/AxisSpec.hpp"
0020 #include "Acts/Utilities/BinUtility.hpp"
0021 #include "Acts/Utilities/IAxis.hpp"
0022 #include "Acts/Utilities/MultiAxisSpec.hpp"
0023 #include "ActsPlugins/Json/SurfaceMaterialJsonConverter.hpp"
0024 #include "ActsPlugins/Json/detail/MaterialJsonContext.hpp"
0025 #include "ActsTests/CommonHelpers/FloatComparisons.hpp"
0026 
0027 #include <array>
0028 #include <memory>
0029 #include <numbers>
0030 #include <stdexcept>
0031 #include <variant>
0032 #include <vector>
0033 
0034 #include <nlohmann/json.hpp>
0035 
0036 using namespace Acts;
0037 
0038 namespace ActsTests {
0039 
0040 namespace {
0041 
0042 /// A few material slabs shared by the index based tests
0043 std::vector<MaterialSlab> testSlabs() {
0044   std::vector<MaterialSlab> material;
0045   material.emplace_back(Material::Vacuum(), 0.0);
0046   material.emplace_back(Material::fromMolarDensity(1.0, 2.0, 3.0, 4.0, 5.0),
0047                         1.0);
0048   material.emplace_back(
0049       Material::fromMolarDensity(11.0, 12.0, 13.0, 14.0, 15.0), 2.0);
0050   material.emplace_back(
0051       Material::fromMolarDensity(21.0, 22.0, 23.0, 24.0, 25.0), 3.0);
0052   return material;
0053 }
0054 
0055 /// Grid material is always 2D now, these are the axes the tests bin on
0056 std::unique_ptr<IAxis> testAxis0() {
0057   return IAxis::createEquidistant(AxisBoundaryType::Bound, -1., 1., 2);
0058 }
0059 
0060 std::unique_ptr<IAxis> testAxis1() {
0061   return IAxis::createEquidistant(AxisBoundaryType::Closed, -std::numbers::pi,
0062                                   std::numbers::pi, 4);
0063 }
0064 
0065 /// Index payload in column major order, i.e. [i0][i1]. Index 0 is vacuum and
0066 /// several bins share an entry, which is what the index storage is for.
0067 std::vector<std::vector<std::size_t>> testIndexPayload() {
0068   return {std::vector<std::size_t>{1u, 1u, 0u, 2u},
0069           std::vector<std::size_t>{0u, 3u, 3u, 0u}};
0070 }
0071 
0072 std::unique_ptr<GridSurfaceMaterial> makeIndexed() {
0073   auto axis0 = testAxis0();
0074   auto axis1 = testAxis1();
0075   return GridSurfaceMaterial::createIndexed(*axis0, *axis1, testSlabs(),
0076                                             testIndexPayload());
0077 }
0078 
0079 std::unique_ptr<GridSurfaceMaterial> makeGloballyIndexed(
0080     std::shared_ptr<std::vector<MaterialSlab>> store = nullptr) {
0081   if (store == nullptr) {
0082     store = std::make_shared<std::vector<MaterialSlab>>(testSlabs());
0083   }
0084   auto axis0 = testAxis0();
0085   auto axis1 = testAxis1();
0086   return GridSurfaceMaterial::createGloballyIndexed(
0087       *axis0, *axis1, std::move(store), testIndexPayload());
0088 }
0089 
0090 std::unique_ptr<GridSurfaceMaterial> makeDirect() {
0091   auto slabs = testSlabs();
0092   std::vector<std::vector<MaterialSlab>> payload{
0093       {slabs[1], slabs[1], slabs[0], slabs[2]},
0094       {slabs[0], slabs[3], slabs[3], slabs[0]}};
0095   auto axis0 = testAxis0();
0096   auto axis1 = testAxis1();
0097   return GridSurfaceMaterial::createDirect(*axis0, *axis1, payload);
0098 }
0099 
0100 /// The local points that address the four phi bins of the two z bins
0101 std::vector<Vector2> testPoints() {
0102   return {{-0.5, -std::numbers::pi * 0.75}, {-0.5, -std::numbers::pi / 4.},
0103           {-0.5, std::numbers::pi / 4.},    {-0.5, std::numbers::pi * 0.75},
0104           {0.5, -std::numbers::pi * 0.75},  {0.5, -std::numbers::pi / 4.},
0105           {0.5, std::numbers::pi / 4.},     {0.5, std::numbers::pi * 0.75}};
0106 }
0107 
0108 BinUtility testBinUtility2D() {
0109   BinUtility bUtility(2, -1., 1., open, AxisDirection::AxisX);
0110   bUtility += BinUtility(3, -3., 3., open, AxisDirection::AxisY);
0111   return bUtility;
0112 }
0113 
0114 /// The matrix is indexed [bin of the second binning][bin of the first]
0115 MaterialSlabMatrix testMatrix2D() {
0116   auto slabs = testSlabs();
0117   MaterialSlabMatrix matrix;
0118   for (std::size_t i1 = 0; i1 < 3; ++i1) {
0119     MaterialSlabVector row;
0120     for (std::size_t i0 = 0; i0 < 2; ++i0) {
0121       row.push_back(slabs[(i1 * 2 + i0) % slabs.size()]);
0122     }
0123     matrix.push_back(std::move(row));
0124   }
0125   return matrix;
0126 }
0127 
0128 /// Round trip a material through the converter
0129 std::unique_ptr<const ISurfaceMaterial> roundTrip(
0130     const ISurfaceMaterial& material) {
0131   nlohmann::json jMaterial = SurfaceMaterialJsonConverter::toJson(material);
0132   return SurfaceMaterialJsonConverter::fromJson(jMaterial);
0133 }
0134 
0135 }  // namespace
0136 
0137 BOOST_AUTO_TEST_SUITE(JsonSuite)
0138 
0139 BOOST_AUTO_TEST_CASE(HomogeneousSurfaceMaterialRoundTrip) {
0140   HomogeneousSurfaceMaterial hsm(
0141       MaterialSlab(Material::fromMolarDensity(1.0, 2.0, 3.0, 4.0, 5.0), 1.5),
0142       1., MappingType::PostMapping);
0143 
0144   nlohmann::json jMaterial = SurfaceMaterialJsonConverter::toJson(hsm);
0145   BOOST_CHECK_EQUAL(jMaterial["type"], "homogeneous");
0146 
0147   auto read = roundTrip(hsm);
0148   BOOST_REQUIRE(read != nullptr);
0149   const auto* typed =
0150       dynamic_cast<const HomogeneousSurfaceMaterial*>(read.get());
0151   BOOST_REQUIRE(typed != nullptr);
0152   BOOST_CHECK(typed->mappingType() == MappingType::PostMapping);
0153   CHECK_CLOSE_ABS(typed->materialSlab(Vector2{0., 0.}).thickness(), 1.5, 1e-5);
0154 }
0155 
0156 BOOST_AUTO_TEST_CASE(BinnedSurfaceMaterialRoundTrip) {
0157   BinnedSurfaceMaterial bsm(testBinUtility2D(), testMatrix2D(), 1.,
0158                             MappingType::Sensor);
0159 
0160   nlohmann::json jMaterial = SurfaceMaterialJsonConverter::toJson(bsm);
0161   BOOST_CHECK_EQUAL(jMaterial["type"], "binned");
0162 
0163   auto read = roundTrip(bsm);
0164   BOOST_REQUIRE(read != nullptr);
0165   const auto* typed = dynamic_cast<const BinnedSurfaceMaterial*>(read.get());
0166   BOOST_REQUIRE(typed != nullptr);
0167   BOOST_CHECK(typed->mappingType() == MappingType::Sensor);
0168   BOOST_CHECK(typed->binUtility() == bsm.binUtility());
0169 
0170   for (double x : {-0.5, 0.5}) {
0171     for (double y : {-2., 0., 2.}) {
0172       Vector2 lp{x, y};
0173       CHECK_CLOSE_ABS(typed->materialSlab(lp).thickness(),
0174                       bsm.materialSlab(lp).thickness(), 1e-5);
0175     }
0176   }
0177 }
0178 
0179 BOOST_AUTO_TEST_CASE(ProtoSurfaceMaterialRoundTrip) {
0180   ProtoSurfaceMaterial psm(testBinUtility2D(), MappingType::PreMapping);
0181 
0182   nlohmann::json jMaterial = SurfaceMaterialJsonConverter::toJson(psm);
0183   BOOST_CHECK_EQUAL(jMaterial["type"], "proto");
0184   BOOST_CHECK_EQUAL(jMaterial["mapMaterial"], true);
0185 
0186   auto read = roundTrip(psm);
0187   BOOST_REQUIRE(read != nullptr);
0188   const auto* typed = dynamic_cast<const ProtoSurfaceMaterial*>(read.get());
0189   BOOST_REQUIRE(typed != nullptr);
0190   BOOST_CHECK(typed->mappingType() == MappingType::PreMapping);
0191   BOOST_CHECK(typed->binning() == psm.binning());
0192 }
0193 
0194 BOOST_AUTO_TEST_CASE(ProtoGridSurfaceMaterialRoundTrip) {
0195   MultiAxisSpec2D spec{std::array<AxisSpec, 2u>{
0196       AxisSpec::Equidistant(4u, -1., 1., AxisBoundaryType::Bound,
0197                             AxisDirection::AxisX),
0198       AxisSpec::DeferredVariable({0., 0.25, 1.}, AxisBoundaryType::Bound,
0199                                  AxisDirection::AxisY)}};
0200   ProtoGridSurfaceMaterial pgsm(spec, MappingType::PostMapping);
0201 
0202   nlohmann::json jMaterial = SurfaceMaterialJsonConverter::toJson(pgsm);
0203   BOOST_CHECK_EQUAL(jMaterial["type"], "proto-grid");
0204 
0205   auto read = roundTrip(pgsm);
0206   BOOST_REQUIRE(read != nullptr);
0207   const auto* typed = dynamic_cast<const ProtoGridSurfaceMaterial*>(read.get());
0208   BOOST_REQUIRE(typed != nullptr);
0209   BOOST_CHECK(typed->mappingType() == MappingType::PostMapping);
0210   BOOST_CHECK(typed->binning() == pgsm.binning());
0211 }
0212 
0213 BOOST_AUTO_TEST_CASE(MergedMaterialMarkerRoundTrip) {
0214   MergedMaterialMarker marker;
0215 
0216   nlohmann::json jMaterial = SurfaceMaterialJsonConverter::toJson(marker);
0217   BOOST_CHECK_EQUAL(jMaterial["type"], "merged-material-marker");
0218 
0219   auto read = roundTrip(marker);
0220   BOOST_REQUIRE(read != nullptr);
0221   BOOST_CHECK(dynamic_cast<const MergedMaterialMarker*>(read.get()) != nullptr);
0222 }
0223 
0224 BOOST_AUTO_TEST_CASE(IndexedGridMaterialRoundTrip) {
0225   auto ism = makeIndexed();
0226 
0227   nlohmann::json jMaterial = SurfaceMaterialJsonConverter::toJson(*ism);
0228   BOOST_CHECK_EQUAL(jMaterial["type"], "grid");
0229   BOOST_CHECK_EQUAL(jMaterial["accessor"]["type"], "indexed");
0230   BOOST_CHECK_EQUAL(jMaterial["accessor"]["grid"]["axes"].size(), 2u);
0231   // The delegates are gone with the multi-axis migration
0232   BOOST_CHECK(!jMaterial.contains("bound_to_grid_local"));
0233   BOOST_CHECK(!jMaterial.contains("global_to_grid_local"));
0234 
0235   auto read = roundTrip(*ism);
0236   BOOST_REQUIRE(read != nullptr);
0237   const auto* typed = dynamic_cast<const GridSurfaceMaterial*>(read.get());
0238   BOOST_REQUIRE(typed != nullptr);
0239   const auto& indexed =
0240       std::get<GridSurfaceMaterial::Indexed>(typed->storage());
0241   BOOST_CHECK_EQUAL(indexed.material.size(), testSlabs().size());
0242 
0243   for (const Vector2& lp : testPoints()) {
0244     CHECK_CLOSE_ABS(typed->materialSlab(lp).thickness(),
0245                     ism->materialSlab(lp).thickness(), 1e-5);
0246   }
0247 }
0248 
0249 BOOST_AUTO_TEST_CASE(GloballyIndexedGridMaterialRoundTrip) {
0250   auto gism = makeGloballyIndexed();
0251 
0252   nlohmann::json jMaterial = SurfaceMaterialJsonConverter::toJson(*gism);
0253   BOOST_CHECK_EQUAL(jMaterial["type"], "grid");
0254   BOOST_CHECK_EQUAL(jMaterial["accessor"]["type"], "globally_indexed");
0255   // The store travels with the payload, so this reads back standalone. The
0256   // free-function reader on main refuses this case outright.
0257   BOOST_CHECK(jMaterial["accessor"].contains("storage_vector"));
0258   BOOST_CHECK(!jMaterial["accessor"].contains("store"));
0259 
0260   auto read = roundTrip(*gism);
0261   BOOST_REQUIRE(read != nullptr);
0262   const auto* typed = dynamic_cast<const GridSurfaceMaterial*>(read.get());
0263   BOOST_REQUIRE(typed != nullptr);
0264   // The globally indexed storage must survive, and its store must be filled
0265   const auto& global =
0266       std::get<GridSurfaceMaterial::GloballyIndexed>(typed->storage());
0267   BOOST_REQUIRE(global.material != nullptr);
0268   BOOST_CHECK_EQUAL(global.material->size(), testSlabs().size());
0269 
0270   for (const Vector2& lp : testPoints()) {
0271     CHECK_CLOSE_ABS(typed->materialSlab(lp).thickness(),
0272                     gism->materialSlab(lp).thickness(), 1e-5);
0273   }
0274 }
0275 
0276 BOOST_AUTO_TEST_CASE(GloballyIndexedSharedStoreThroughContext) {
0277   auto store = std::make_shared<std::vector<MaterialSlab>>(testSlabs());
0278   auto first = makeGloballyIndexed(store);
0279   auto second = makeGloballyIndexed(store);
0280 
0281   auto encodeContext =
0282       SurfaceMaterialJsonConverter::EncodeContext::withStoreTable();
0283   const auto& config = SurfaceMaterialJsonConverter::Config::defaultConfig();
0284   nlohmann::json jFirst =
0285       SurfaceMaterialJsonConverter::toJson(*first, config, &encodeContext);
0286   nlohmann::json jSecond =
0287       SurfaceMaterialJsonConverter::toJson(*second, config, &encodeContext);
0288 
0289   // One table entry, referenced by both surfaces
0290   BOOST_REQUIRE_EQUAL(encodeContext.stores().size(), 1u);
0291   BOOST_CHECK(encodeContext.stores()[0] == store);
0292   BOOST_CHECK_EQUAL(jFirst["accessor"]["store"], 0u);
0293   BOOST_CHECK_EQUAL(jSecond["accessor"]["store"], 0u);
0294   BOOST_CHECK(!jFirst["accessor"].contains("storage_vector"));
0295   BOOST_CHECK(!jSecond["accessor"].contains("storage_vector"));
0296 
0297   SurfaceMaterialJsonConverter::DecodeContext decodeContext;
0298   decodeContext.setStores(
0299       {std::make_shared<std::vector<MaterialSlab>>(testSlabs())});
0300 
0301   auto readFirst =
0302       SurfaceMaterialJsonConverter::fromJson(jFirst, config, &decodeContext);
0303   auto readSecond =
0304       SurfaceMaterialJsonConverter::fromJson(jSecond, config, &decodeContext);
0305   BOOST_REQUIRE(readFirst != nullptr);
0306   BOOST_REQUIRE(readSecond != nullptr);
0307 
0308   const auto& globalFirst = std::get<GridSurfaceMaterial::GloballyIndexed>(
0309       dynamic_cast<const GridSurfaceMaterial&>(*readFirst).storage());
0310   const auto& globalSecond = std::get<GridSurfaceMaterial::GloballyIndexed>(
0311       dynamic_cast<const GridSurfaceMaterial&>(*readSecond).storage());
0312   // The sharing must survive the round trip
0313   BOOST_CHECK(globalFirst.material == globalSecond.material);
0314   BOOST_CHECK(globalFirst.material == decodeContext.store(0u));
0315 }
0316 
0317 BOOST_AUTO_TEST_CASE(DistinctStoresGetSequentialIds) {
0318   auto storeA = std::make_shared<std::vector<MaterialSlab>>(testSlabs());
0319   // Same content, different allocation: stores are keyed on identity
0320   auto storeB = std::make_shared<std::vector<MaterialSlab>>(testSlabs());
0321 
0322   auto ctx = SurfaceMaterialJsonConverter::EncodeContext::withStoreTable();
0323   const auto& config = SurfaceMaterialJsonConverter::Config::defaultConfig();
0324   nlohmann::json jA = SurfaceMaterialJsonConverter::toJson(
0325       *makeGloballyIndexed(storeA), config, &ctx);
0326   nlohmann::json jB = SurfaceMaterialJsonConverter::toJson(
0327       *makeGloballyIndexed(storeB), config, &ctx);
0328   nlohmann::json jA2 = SurfaceMaterialJsonConverter::toJson(
0329       *makeGloballyIndexed(storeA), config, &ctx);
0330 
0331   BOOST_CHECK_EQUAL(jA["accessor"]["store"], 0u);
0332   BOOST_CHECK_EQUAL(jB["accessor"]["store"], 1u);
0333   BOOST_CHECK_EQUAL(jA2["accessor"]["store"], 0u);
0334   BOOST_REQUIRE_EQUAL(ctx.stores().size(), 2u);
0335   BOOST_CHECK(ctx.stores()[0] == storeA);
0336   BOOST_CHECK(ctx.stores()[1] == storeB);
0337 }
0338 
0339 BOOST_AUTO_TEST_CASE(StoreReferenceWithoutTableThrows) {
0340   auto store = std::make_shared<std::vector<MaterialSlab>>(testSlabs());
0341   auto ctx = SurfaceMaterialJsonConverter::EncodeContext::withStoreTable();
0342   const auto& config = SurfaceMaterialJsonConverter::Config::defaultConfig();
0343   nlohmann::json jMaterial = SurfaceMaterialJsonConverter::toJson(
0344       *makeGloballyIndexed(store), config, &ctx);
0345 
0346   // A default decode context has no table at all
0347   BOOST_CHECK_THROW(SurfaceMaterialJsonConverter::fromJson(jMaterial),
0348                     std::invalid_argument);
0349 
0350   // A table that does not reach the referenced id
0351   SurfaceMaterialJsonConverter::DecodeContext empty;
0352   empty.setStores({});
0353   BOOST_CHECK_THROW(
0354       SurfaceMaterialJsonConverter::fromJson(jMaterial, config, &empty),
0355       std::invalid_argument);
0356 
0357   nlohmann::json jOutOfRange = jMaterial;
0358   jOutOfRange["accessor"]["store"] = 7u;
0359   SurfaceMaterialJsonConverter::DecodeContext oneEntry;
0360   oneEntry.setStores({store});
0361   BOOST_CHECK_THROW(
0362       SurfaceMaterialJsonConverter::fromJson(jOutOfRange, config, &oneEntry),
0363       std::invalid_argument);
0364 }
0365 
0366 BOOST_AUTO_TEST_CASE(DirectGridMaterialRoundTrip) {
0367   auto gsm = makeDirect();
0368 
0369   nlohmann::json jMaterial = SurfaceMaterialJsonConverter::toJson(*gsm);
0370   BOOST_CHECK_EQUAL(jMaterial["type"], "grid");
0371   BOOST_CHECK_EQUAL(jMaterial["accessor"]["type"], "direct");
0372   BOOST_CHECK(!jMaterial["accessor"].contains("storage_vector"));
0373 
0374   auto read = roundTrip(*gsm);
0375   BOOST_REQUIRE(read != nullptr);
0376   const auto* typed = dynamic_cast<const GridSurfaceMaterial*>(read.get());
0377   BOOST_REQUIRE(typed != nullptr);
0378   BOOST_CHECK(
0379       std::holds_alternative<GridSurfaceMaterial::Direct>(typed->storage()));
0380 
0381   for (const Vector2& lp : testPoints()) {
0382     CHECK_CLOSE_ABS(typed->materialSlab(lp).thickness(),
0383                     gsm->materialSlab(lp).thickness(), 1e-5);
0384   }
0385 }
0386 
0387 BOOST_AUTO_TEST_CASE(EncoderCoversAllSurfaceMaterials) {
0388   const auto& cfg = SurfaceMaterialJsonConverter::Config::defaultConfig();
0389 
0390   std::vector<std::shared_ptr<const ISurfaceMaterial>> materials;
0391   materials.push_back(std::make_shared<const HomogeneousSurfaceMaterial>(
0392       MaterialSlab(Material::fromMolarDensity(1.0, 2.0, 3.0, 4.0, 5.0), 1.)));
0393   materials.push_back(std::make_shared<const BinnedSurfaceMaterial>(
0394       testBinUtility2D(), testMatrix2D()));
0395   materials.push_back(
0396       std::make_shared<const ProtoSurfaceMaterial>(testBinUtility2D()));
0397   materials.push_back(std::make_shared<const ProtoGridSurfaceMaterial>(
0398       MultiAxisSpec2D{std::array<AxisSpec, 2u>{
0399           AxisSpec::Equidistant(2u, 0., 1., AxisBoundaryType::Bound,
0400                                 AxisDirection::AxisX),
0401           AxisSpec::Equidistant(2u, 0., 1., AxisBoundaryType::Bound,
0402                                 AxisDirection::AxisY)}}));
0403   materials.push_back(std::make_shared<const MergedMaterialMarker>());
0404   materials.push_back(makeIndexed());
0405   materials.push_back(makeGloballyIndexed());
0406   materials.push_back(makeDirect());
0407 
0408   for (std::size_t im = 0; im < materials.size(); ++im) {
0409     const auto& material = materials[im];
0410     BOOST_TEST_CONTEXT("material " << im) {
0411       // Exactly one encoder must claim the type, otherwise the call throws
0412       BOOST_CHECK(cfg.encoder.hasFunction(*material));
0413       nlohmann::json jMaterial;
0414       BOOST_REQUIRE_NO_THROW(
0415           jMaterial = SurfaceMaterialJsonConverter::toJson(*material));
0416       // Every tag the encoder can emit must be known to the decoder
0417       BOOST_CHECK(cfg.decoder.hasKind(jMaterial["type"].get<std::string>()));
0418     }
0419   }
0420 
0421   // One concrete class carries the whole grid material family
0422   BOOST_CHECK(cfg.encoder.hasFunction<HomogeneousSurfaceMaterial>());
0423   BOOST_CHECK(cfg.encoder.hasFunction<BinnedSurfaceMaterial>());
0424   BOOST_CHECK(cfg.encoder.hasFunction<ProtoSurfaceMaterial>());
0425   BOOST_CHECK(cfg.encoder.hasFunction<ProtoGridSurfaceMaterial>());
0426   BOOST_CHECK(cfg.encoder.hasFunction<MergedMaterialMarker>());
0427   BOOST_CHECK(cfg.encoder.hasFunction<GridSurfaceMaterial>());
0428   BOOST_CHECK_EQUAL(cfg.encoder.size(), 6u);
0429   BOOST_CHECK_EQUAL(cfg.decoder.size(), 6u);
0430 }
0431 
0432 BOOST_AUTO_TEST_CASE(MissingAndUnknownTypeTagThrow) {
0433   nlohmann::json jMissing;
0434   jMissing["mapMaterial"] = true;
0435   BOOST_CHECK_THROW(SurfaceMaterialJsonConverter::fromJson(jMissing),
0436                     std::invalid_argument);
0437 
0438   nlohmann::json jUnknown;
0439   jUnknown["mapMaterial"] = true;
0440   jUnknown["type"] = "not-a-material";
0441   BOOST_CHECK_THROW(SurfaceMaterialJsonConverter::fromJson(jUnknown),
0442                     std::invalid_argument);
0443 }
0444 
0445 BOOST_AUTO_TEST_CASE(UnmappedMaterialYieldsNoMaterial) {
0446   nlohmann::json jMaterial;
0447   jMaterial["type"] = "proto";
0448   jMaterial["mapMaterial"] = false;
0449   BOOST_CHECK(SurfaceMaterialJsonConverter::fromJson(jMaterial) == nullptr);
0450 
0451   // A proto material without binning is flagged as not mapped on write
0452   ProtoSurfaceMaterial psm{BinUtility{}};
0453   nlohmann::json jProto = SurfaceMaterialJsonConverter::toJson(psm);
0454   BOOST_CHECK_EQUAL(jProto["mapMaterial"], false);
0455   BOOST_CHECK(SurfaceMaterialJsonConverter::fromJson(jProto) == nullptr);
0456 }
0457 
0458 BOOST_AUTO_TEST_SUITE_END()
0459 
0460 }  // namespace ActsTests