959 {
962 std::ifstream ini_file(file_name.c_str(), std::ifstream::in);
963 po::variables_map vm;
964 if (clean_file_options) {
966 boost::shared_ptr<boost::program_options::options_description>(
967 new po::options_description());
968 }
969
970 auto add_block_attributes = [&](auto prefix, auto &block_lists, auto &it) {
971
973 (prefix + ".number_of_attributes").c_str(),
974 po::value<int>(&block_lists[it->getMeshsetId()].numberOfAttributes)
975 ->default_value(-1),
976 "Number of blockset attributes")(
977 (prefix + ".user_array").c_str(), po::value<string>(),
978 "Add block attributes as comma separated list");
979 for (int ii = 1; ii <= 10; ii++) {
980 std::string surfix = ".user" + boost::lexical_cast<std::string>(ii);
982 (prefix + surfix).c_str(),
983 po::value<double>(&block_lists[it->getMeshsetId()].aTtr[ii - 1])
984 ->default_value(0.0),
985 "Add block attribute");
986 }
987 };
988
989
990 map<int, BlockData> block_lists;
992 const auto id = it->getMeshsetId();
993 block_lists[id].cubitMeshset = it->getMeshset();
994 std::string prefix =
995 "block_" + boost::lexical_cast<std::string>(id);
997 (prefix + ".add").c_str(),
998 po::value<string>(&block_lists[it->getMeshsetId()].addType)
999 ->default_value("UNKNOWNSET"),
1000 "Add block set")(
1001 (prefix + ".id").c_str(),
1002 po::value<int>(&block_lists[it->getMeshsetId()].iD)->default_value(-1),
1003 "Id of meshset")(
1004 (prefix + ".name").c_str(),
1005 po::value<string>(&block_lists[it->getMeshsetId()].nAme)
1006 ->default_value(""),
1007 "Name of the meshset");
1008
1009
1010 add_block_attributes(prefix, block_lists, it);
1011
1012
1013 {
1014
1015
1016
1018 (prefix + ".young").c_str(),
1019 po::value<double>()->default_value(-1)->notifier(
1020 [&block_lists,
id](
double v) {
1021 block_lists[id].matElastic.data.Young =
v;
1022 }),
1023 "Young modulus")(
1024 (prefix + ".poisson").c_str(),
1025 po::value<double>()->default_value(-2)->notifier(
1026 [&block_lists,
id](
double v) {
1027 block_lists[id].matElastic.data.Poisson =
v;
1028 }),
1029 "Poisson ratio")(
1030 (prefix + ".thermalexpansion").c_str(),
1031 po::value<double>()->default_value(-1)->notifier(
1032 [&block_lists,
id](
double v) {
1033 block_lists[id].matElastic.data.ThermalExpansion =
v;
1034 }),
1035 "Thermal expansion");
1036
1037 }
1038
1039 {
1040
1041
1042
1043
1044
1046 (prefix + ".Youngp").c_str(),
1047 po::value<double>()->default_value(-1)->notifier(
1048 [&block_lists,
id](
double v) {
1049 block_lists[id].matTransIso.data.Youngp =
v;
1050 }),
1051 "Youngp")(
1052 (prefix + ".Youngz").c_str(),
1053 po::value<double>()->default_value(-1)->notifier(
1054 [&block_lists,
id](
double v) {
1055 block_lists[id].matTransIso.data.Youngz =
v;
1056 }),
1057 "Youngz")(
1058 (prefix + ".Poissonp").c_str(),
1059 po::value<double>()->default_value(0)->notifier(
1060 [&block_lists,
id](
double v) {
1061 block_lists[id].matTransIso.data.Poissonp =
v;
1062 }),
1063 "Poissonp")(
1064 (prefix + ".Poissonpz").c_str(),
1065 po::value<double>()->default_value(0)->notifier(
1066 [&block_lists,
id](
double v) {
1067 block_lists[id].matTransIso.data.Poissonpz =
v;
1068 }),
1069 "Poissonpz")(
1070 (prefix + ".Shearzp").c_str(),
1071 po::value<double>()->default_value(-1)->notifier(
1072 [&block_lists,
id](
double v) {
1073 block_lists[id].matTransIso.data.Shearzp =
v;
1074 }),
1075 "Shearzp");
1076
1077 }
1078
1079 {
1080
1081
1083 (prefix + ".conductivity").c_str(),
1084 po::value<double>()->default_value(-1)->notifier(
1085 [&block_lists,
id](
double v) {
1086 block_lists[id].matThermal.data.Conductivity =
v;
1087 }),
1088 "Conductivity")(
1089 (prefix + ".capacity").c_str(),
1090 po::value<double>()->default_value(-1)->notifier(
1091 [&block_lists,
id](
double v) {
1092 block_lists[id].matThermal.data.HeatCapacity =
v;
1093 }),
1094 "Capacity");
1095
1096 }
1097
1098 {
1099
1100
1101
1102
1104 (prefix + ".interface_alpha").c_str(),
1105 po::value<double>()->default_value(-1)->notifier(
1106 [&block_lists,
id](
double v) {
1107 block_lists[id].matInterf.data.alpha =
v;
1108 }),
1109 "alpha")((prefix + ".interface_beta").c_str(),
1110 po::value<double>()->default_value(-1)->notifier(
1111 [&block_lists,
id](
double v) {
1112 block_lists[id].matInterf.data.beta =
v;
1113 }),
1114 "beta")(
1115 (prefix + ".interface_ft").c_str(),
1116 po::value<double>()->default_value(-1)->notifier(
1117 [&block_lists,
id](
double v) {
1118 block_lists[id].matInterf.data.ft =
v;
1119 }),
1120 "ft")(
1121 (prefix + ".interface_Gf").c_str(),
1122 po::value<double>()->default_value(-1)->notifier(
1123 [&block_lists,
id](
double v) {
1124 block_lists[id].matInterf.data.Gf =
v;
1125 }),
1126 "Gf");
1127
1128 }
1129
1130
1131 {
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1145 (prefix + ".disp_flag1").c_str(),
1146 po::value<char>()->default_value(0)->notifier(
1147 [&block_lists,
id](
char v) {
1148 block_lists[id].dispBc.data.flag1 =
v;
1149 }),
1150 "flag1")(
1151 (prefix + ".disp_flag2").c_str(),
1152 po::value<char>()->default_value(0)->notifier(
1153 [&block_lists,
id](
char v) {
1154 block_lists[id].dispBc.data.flag2 =
v;
1155 }),
1156 "flag2")(
1157 (prefix + ".disp_flag3").c_str(),
1158 po::value<char>()->default_value(0)->notifier(
1159 [&block_lists,
id](
char v) {
1160 block_lists[id].dispBc.data.flag3 =
v;
1161 }),
1162 "flag3")(
1163 (prefix + ".disp_flag4").c_str(),
1164 po::value<char>()->default_value(0)->notifier(
1165 [&block_lists,
id](
char v) {
1166 block_lists[id].dispBc.data.flag4 =
v;
1167 }),
1168 "flag4")(
1169 (prefix + ".disp_flag5").c_str(),
1170 po::value<char>()->default_value(0)->notifier(
1171 [&block_lists,
id](
char v) {
1172 block_lists[id].dispBc.data.flag5 =
v;
1173 }),
1174 "flag5")(
1175 (prefix + ".disp_flag6").c_str(),
1176 po::value<char>()->default_value(0)->notifier(
1177 [&block_lists,
id](
char v) {
1178 block_lists[id].dispBc.data.flag6 =
v;
1179 }),
1180 "flag6")(
1181 (prefix + ".disp_ux").c_str(),
1182 po::value<double>()->default_value(0)->notifier(
1183 [&block_lists,
id](
double v) {
1184 block_lists[id].dispBc.data.value1 =
v;
1185 }),
1186 "value1")(
1187 (prefix + ".disp_uy").c_str(),
1188 po::value<double>()->default_value(0)->notifier(
1189 [&block_lists,
id](
double v) {
1190 block_lists[id].dispBc.data.value2 =
v;
1191 }),
1192 "value2")(
1193 (prefix + ".disp_uz").c_str(),
1194 po::value<double>()->default_value(0)->notifier(
1195 [&block_lists,
id](
double v) {
1196 block_lists[id].dispBc.data.value3 =
v;
1197 }),
1198 "value3")(
1199 (prefix + ".disp_rx").c_str(),
1200 po::value<double>()->default_value(0)->notifier(
1201 [&block_lists,
id](
double v) {
1202 block_lists[id].dispBc.data.value4 =
v;
1203 }),
1204 "value4")(
1205 (prefix + ".disp_ry").c_str(),
1206 po::value<double>()->default_value(0)->notifier(
1207 [&block_lists,
id](
double v) {
1208 block_lists[id].dispBc.data.value5 =
v;
1209 }),
1210 "value5")(
1211 (prefix + ".disp_rz").c_str(),
1212 po::value<double>()->default_value(0)->notifier(
1213 [&block_lists,
id](
double v) {
1214 block_lists[id].dispBc.data.value6 =
v;
1215 }),
1216 "value6");
1217 }
1218
1219 {
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1231 (prefix + ".force_magnitude").c_str(),
1232 po::value<double>()->default_value(0)->notifier(
1233 [&block_lists,
id](
double v) {
1234 block_lists[id].forceBc.data.value1 =
v;
1235 }),
1236 "value1")((prefix + ".moment_magnitude").c_str(),
1237 po::value<double>()->default_value(0)->notifier(
1238 [&block_lists,
id](
double v) {
1239 block_lists[id].forceBc.data.value2 =
v;
1240 }),
1241 "value2")(
1242 (prefix + ".force_fx").c_str(),
1243 po::value<double>()->default_value(0)->notifier(
1244 [&block_lists,
id](
double v) {
1245 block_lists[id].forceBc.data.value3 =
v;
1246 }),
1247 "value3")((prefix + ".force_fy").c_str(),
1248 po::value<double>()->default_value(0)->notifier(
1249 [&block_lists,
id](
double v) {
1250 block_lists[id].forceBc.data.value4 =
v;
1251 }),
1252 "value4")(
1253 (prefix + ".force_fz").c_str(),
1254 po::value<double>()->default_value(0)->notifier(
1255 [&block_lists,
id](
double v) {
1256 block_lists[id].forceBc.data.value5 =
v;
1257 }),
1258 "value5")((prefix + ".moment_mx").c_str(),
1259 po::value<double>()->default_value(0)->notifier(
1260 [&block_lists,
id](
double v) {
1261 block_lists[id].forceBc.data.value6 =
v;
1262 }),
1263 "value6")(
1264 (prefix + ".moment_my").c_str(),
1265 po::value<double>()->default_value(0)->notifier(
1266 [&block_lists,
id](
double v) {
1267 block_lists[id].forceBc.data.value7 =
v;
1268 }),
1269 "value7")((prefix + ".moment_mz").c_str(),
1270 po::value<double>()->default_value(0)->notifier(
1271 [&block_lists,
id](
double v) {
1272 block_lists[id].forceBc.data.value8 =
v;
1273 }),
1274 "value8");
1275 }
1276 {
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1293 (prefix + ".temperature_flag1").c_str(),
1294 po::value<char>()->default_value(0)->notifier(
1295 [&block_lists,
id](
char v) {
1296 block_lists[id].temperatureBc.data.flag1 =
v;
1297 }),
1298 "flag1")(
1299 (prefix + ".temperature_t").c_str(),
1300 po::value<double>()->default_value(0)->notifier(
1301 [&block_lists,
id](
double v) {
1302 block_lists[id].temperatureBc.data.value1 =
v;
1303 }),
1304 "value1");
1305
1306 }
1307
1308 {
1309
1310
1311
1312
1313
1315 (prefix + ".pressure_flag2").c_str(),
1316 po::value<char>()->default_value(0)->notifier(
1317 [&block_lists,
id](
char v) {
1318 block_lists[id].pressureBc.data.flag2 =
v;
1319 }),
1320 "flag2")((prefix + ".pressure_magnitude").c_str(),
1321 po::value<double>()->default_value(0)->notifier(
1322 [&block_lists,
id](
double v) {
1323 block_lists[id].pressureBc.data.value1 =
v;
1324 }),
1325 "value1");
1326 }
1327 {
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1339 (prefix + ".heatflux_flag1").c_str(),
1340 po::value<char>()->default_value(0)->notifier(
1341 [&block_lists,
id](
char v) {
1342 block_lists[id].heatFluxBc.data.flag1 =
v;
1343 }),
1344 "flag1")((prefix + ".heatflux_magnitude").c_str(),
1345 po::value<double>()->default_value(0)->notifier(
1346 [&block_lists,
id](
double v) {
1347 block_lists[id].heatFluxBc.data.value1 =
v;
1348 }),
1349 "value1");
1350 }
1351
1352 {
1354 (prefix + ".interface_type").c_str(),
1355 po::value<char>()->default_value(0)->notifier(
1356 [&block_lists,
id](
char v) {
1357 block_lists[id].cfgBc.data.type =
v;
1358 }),
1359 "type");
1360 }
1361 }
1362
1363 map<int, BlockData> block_set_attributes;
1365 block_set_attributes[it->getMeshsetId()].cubitMeshset = it->getMeshset();
1366 block_set_attributes[it->getMeshsetId()].iD = it->getMeshsetId();
1367 block_set_attributes[it->getMeshsetId()].bcType =
BLOCKSET;
1368 std::string block_name = it->getName();
1369 block_name.erase(
1370 std::remove_if(block_name.begin(), block_name.end(), ::isspace),
1371 block_name.end());
1372 block_set_attributes[it->getMeshsetId()].nAme = block_name;
1373
1374 if (block_name.compare("NoNameSet") != 0) {
1375 std::string prefix = "SET_ATTR_" + block_name;
1376
1377 add_block_attributes(prefix, block_set_attributes, it);
1378 }
1379 }
1380
1381 po::parsed_options parsed =
1383 store(parsed, vm);
1384 po::notify(vm);
1385
1386 auto parse_attributes_array = [&](const std::string &option_name,
1387 const std::string &values,
1388 std::vector<double> &attributes) {
1389 attributes.clear();
1390 std::string normalized = values;
1391 for (
auto &
c : normalized) {
1392 if (
c ==
',' ||
c ==
'[' ||
c ==
']')
1394 }
1395
1396 std::stringstream ss(normalized);
1397 double value;
1398 while (ss >> value) {
1399 attributes.push_back(value);
1400 }
1401 if (!ss.eof()) {
1403 "Invalid value for %s: %s", option_name.c_str(),
1404 values.c_str());
1405 }
1406 return 0;
1407 };
1408
1409 auto apply_attributes_array = [&](const std::string &prefix,
1411 const auto option_name = prefix + ".user_array";
1412 if (vm.count(option_name)) {
1413 CHKERR parse_attributes_array(option_name, vm[option_name].as<string>(),
1414 block_data.aTtr);
1415 block_data.numberOfAttributes = static_cast<int>(block_data.aTtr.size());
1416 } else if (block_data.numberOfAttributes > -1) {
1417 block_data.aTtr.resize(block_data.numberOfAttributes, 0);
1418 }
1419 return 0;
1420 };
1421
1422 for (auto &block : block_lists) {
1423 const std::string prefix =
1424 "block_" + boost::lexical_cast<std::string>(block.first);
1425 CHKERR apply_attributes_array(prefix, block.second);
1426 }
1427 for (auto &set_attr : block_set_attributes) {
1428 if (set_attr.second.nAme.compare("NoNameSet") != 0) {
1429 const std::string prefix = "SET_ATTR_" + set_attr.second.nAme;
1430 CHKERR apply_attributes_array(prefix, set_attr.second);
1431 }
1432 }
1433
1434
1436
1438 unsigned jj = 0;
1441 block_lists[it->getMeshsetId()].addType) {
1442 bc_type = 1 << jj;
1443 }
1444 ++jj;
1445 }
1446 if (bc_type.none()) {
1447 block_lists[it->getMeshsetId()].bcType =
UNKNOWNSET;
1448
1449 continue;
1450 }
1451
1452 if (bc_type.to_ulong() ==
BLOCKSET)
1453 block_lists[it->getMeshsetId()].bcType =
BLOCKSET;
1454 else if (bc_type.to_ulong() ==
NODESET)
1455 block_lists[it->getMeshsetId()].bcType =
NODESET;
1456 else if (bc_type.to_ulong() ==
SIDESET)
1457 block_lists[it->getMeshsetId()].bcType =
SIDESET;
1458 else {
1460 "Not yet implemented type %s\n",
1461 block_lists[it->getMeshsetId()].addType.c_str());
1462 }
1463 if (block_lists[it->getMeshsetId()].iD == -1) {
1465 "Unset iD number %d\n", block_lists[it->getMeshsetId()].iD);
1466 }
1467 }
1468
1469 std::vector<std::string> additional_parameters;
1470 additional_parameters =
1471 collect_unrecognized(parsed.options, po::include_positional);
1472 for (std::vector<std::string>::iterator vit = additional_parameters.begin();
1473 vit != additional_parameters.end(); vit++) {
1474 MOFEM_LOG_C(
"MeshsetMngSelf", Sev::warning,
"Unrecognized option %s",
1475 vit->c_str());
1476 }
1477 for (map<int, BlockData>::iterator mit = block_lists.begin();
1478 mit != block_lists.end(); mit++) {
1479 CubitMeshSet_multiIndex::iterator cubit_meshset_it =
1483 "Data inconsistency\n");
1484 }
1485 switch (mit->second.bcType) {
1487 break;
1489 if ((
CubitBCType(mit->second.bcType) & cubit_meshset_it->getBcType())
1490 .any() &&
1491 mit->second.iD == cubit_meshset_it->getMeshsetId()) {
1492
1493 } else {
1497 &meshset, 1);
1498 }
1499
1501
1502
1503 if (mit->second.matElastic.data.Young != -1) {
1505 mit->second.matElastic);
1506 }
1507 if (mit->second.matTransIso.data.Youngp != -1) {
1509 mit->second.matTransIso);
1510 }
1511 if (mit->second.matThermal.data.Conductivity != -1) {
1513 mit->second.matThermal);
1514 }
1515 if (mit->second.matInterf.data.ft != -1) {
1517 mit->second.matInterf);
1518 }
1519 } break;
1521 if ((
CubitBCType(mit->second.bcType) & cubit_meshset_it->getBcType())
1522 .any() &&
1523 mit->second.iD == cubit_meshset_it->getMeshsetId()) {
1524
1525 } else {
1529 &meshset, 1);
1530 }
1531
1532 if (mit->second.dispBc.data.flag1 || mit->second.dispBc.data.flag2 ||
1533 mit->second.dispBc.data.flag3 || mit->second.dispBc.data.flag4 ||
1534 mit->second.dispBc.data.flag5 || mit->second.dispBc.data.flag6) {
1535 if (mit->second.dispBc.data.flag1 == '0')
1536 mit->second.dispBc.data.flag1 = 0;
1537 if (mit->second.dispBc.data.flag1 == 'N')
1538 mit->second.dispBc.data.flag1 = 0;
1539 if (mit->second.dispBc.data.flag1)
1540 mit->second.dispBc.data.flag1 = 1;
1541 if (mit->second.dispBc.data.flag2 == '0')
1542 mit->second.dispBc.data.flag2 = 0;
1543 if (mit->second.dispBc.data.flag2 == 'N')
1544 mit->second.dispBc.data.flag2 = 0;
1545 if (mit->second.dispBc.data.flag2)
1546 mit->second.dispBc.data.flag2 = 1;
1547 if (mit->second.dispBc.data.flag3 == '0')
1548 mit->second.dispBc.data.flag3 = 0;
1549 if (mit->second.dispBc.data.flag3 == 'N')
1550 mit->second.dispBc.data.flag3 = 0;
1551 if (mit->second.dispBc.data.flag3)
1552 mit->second.dispBc.data.flag3 = 1;
1553 if (mit->second.dispBc.data.flag4 == '0')
1554 mit->second.dispBc.data.flag4 = 0;
1555 if (mit->second.dispBc.data.flag4 == 'N')
1556 mit->second.dispBc.data.flag4 = 0;
1557 if (mit->second.dispBc.data.flag4)
1558 mit->second.dispBc.data.flag4 = 1;
1559 if (mit->second.dispBc.data.flag5 == '0')
1560 mit->second.dispBc.data.flag5 = 0;
1561 if (mit->second.dispBc.data.flag5 == 'N')
1562 mit->second.dispBc.data.flag5 = 0;
1563 if (mit->second.dispBc.data.flag5)
1564 mit->second.dispBc.data.flag5 = 1;
1565 if (mit->second.dispBc.data.flag6 == '0')
1566 mit->second.dispBc.data.flag6 = 0;
1567 if (mit->second.dispBc.data.flag6 == 'N')
1568 mit->second.dispBc.data.flag6 = 0;
1569 if (mit->second.dispBc.data.flag6)
1570 mit->second.dispBc.data.flag6 = 1;
1572 mit->second.dispBc);
1573 }
1574 if (mit->second.forceBc.data.value1 != 0 ||
1575 mit->second.forceBc.data.value2 != 0) {
1577 mit->second.forceBc);
1578 }
1579
1580 if (mit->second.temperatureBc.data.flag1) {
1581 if (mit->second.temperatureBc.data.flag1 == '0')
1582 mit->second.temperatureBc.data.flag1 = 0;
1583 if (mit->second.temperatureBc.data.flag1 == 'N')
1584 mit->second.temperatureBc.data.flag1 = 0;
1585 if (mit->second.temperatureBc.data.flag1)
1586 mit->second.temperatureBc.data.flag1 = 1;
1588 mit->second.temperatureBc);
1589 }
1590 } break;
1592 if ((
CubitBCType(mit->second.bcType) & cubit_meshset_it->getBcType())
1593 .any() &&
1594 mit->second.iD == cubit_meshset_it->getMeshsetId()) {
1595
1596 } else {
1600 &meshset, 1);
1601 }
1602
1603 if (mit->second.pressureBc.data.value1 != 0) {
1604 if (mit->second.pressureBc.data.flag2 == '0')
1605 mit->second.pressureBc.data.flag2 = 0;
1606 if (mit->second.pressureBc.data.flag2 == 'N')
1607 mit->second.pressureBc.data.flag2 = 0;
1608 if (mit->second.pressureBc.data.flag2)
1609 mit->second.pressureBc.data.flag2 = 1;
1611 mit->second.pressureBc);
1612 }
1613
1614 if (mit->second.heatFluxBc.data.value1 != 0) {
1615 if (mit->second.heatFluxBc.data.flag1 == '0')
1616 mit->second.heatFluxBc.data.flag1 = 0;
1617 if (mit->second.heatFluxBc.data.flag1 == 'N')
1618 mit->second.heatFluxBc.data.flag1 = 0;
1619 if (mit->second.heatFluxBc.data.flag1)
1620 mit->second.heatFluxBc.data.flag1 = 1;
1622 mit->second.heatFluxBc);
1623 }
1624
1625 if (mit->second.cfgBc.data.type != 0) {
1626 CHKERR setBcData(mit->second.bcType, mit->second.iD, mit->second.cfgBc);
1627 }
1628 } break;
1629 default:
1631 "Not yet implemented type\n");
1632 }
1633 }
1634
1635 for (auto set_attr : block_set_attributes) {
1636
1637 if (set_attr.second.numberOfAttributes > 0) {
1638 MOFEM_LOG(
"MeshsetMngSelf", Sev::verbose)
1639 << "Set attributes to blockset " << set_attr.second.nAme;
1640 set_attr.second.aTtr.resize(set_attr.second.numberOfAttributes);
1642 set_attr.second.aTtr);
1643 }
1644 }
1645
1647}
#define MOFEM_LOG_C(channel, severity, format,...)
static const char *const CubitBCNames[]
Names of types of sets and boundary conditions.
MoFEMErrorCode setBcData(const CubitBCType cubit_bc_type, const int ms_id, const GenericCubitBcData &data)
Set boundary condition data for meshset.
MoFEMErrorCode addEntitiesToMeshset(const CubitBCType cubit_bc_type, const int ms_id, const Range &ents)
Add entities to CUBIT meshset.
MoFEMErrorCode addMeshset(const CubitBCType cubit_bc_type, const int ms_id, const std::string name="")
Add CUBIT meshset to manager.
#define _IT_CUBITMESHSETS_BY_SET_TYPE_FOR_LOOP_(MESHSET_MANAGER, CUBITBCTYPE, IT)
Iterator that loops over a specific Cubit MeshSet having a particular BC meshset in a moFEM field.
const double c
speed of light (cm/ns)
const double v
phase velocity of light in medium (cm/ns)
std::bitset< 32 > CubitBCType