diff --git a/src/dump_custom.cpp b/src/dump_custom.cpp index f0780e9839..e30689f378 100644 --- a/src/dump_custom.cpp +++ b/src/dump_custom.cpp @@ -302,7 +302,7 @@ void DumpCustom::init_style() strcpy(vformat[i],ptr); } - vformat[i] = strcat(vformat[i]," "); + if (i+1 < size_one) vformat[i] = strcat(vformat[i]," "); } // setup boundary string @@ -381,8 +381,83 @@ void DumpCustom::write_header(bigint ndump) /* ---------------------------------------------------------------------- */ +void DumpCustom::format_magic_string_binary() +{ + // use negative ntimestep as marker for new format + bigint fmtlen = strlen(MAGIC_STRING); + bigint marker = -fmtlen; + fwrite(&marker, sizeof(bigint), 1, fp); + fwrite(MAGIC_STRING, sizeof(char), fmtlen, fp); +} + +/* ---------------------------------------------------------------------- */ + +void DumpCustom::format_endian_binary() +{ + int endian = ENDIAN; + fwrite(&endian, sizeof(int), 1, fp); +} + +/* ---------------------------------------------------------------------- */ + +void DumpCustom::format_revision_binary() +{ + int revision = FORMAT_REVISION; + fwrite(&revision, sizeof(int), 1, fp); +} + +/* ---------------------------------------------------------------------- */ + +void DumpCustom::header_unit_style_binary() +{ + int len = 0; + if (unit_flag && !unit_count) { + ++unit_count; + len = strlen(update->unit_style); + fwrite(&len, sizeof(int), 1, fp); + fwrite(update->unit_style, sizeof(char), len, fp); + } else { + fwrite(&len, sizeof(int), 1, fp); + } +} + +/* ---------------------------------------------------------------------- */ + +void DumpCustom::header_columns_binary() +{ + int len = strlen(columns); + fwrite(&len, sizeof(int), 1, fp); + fwrite(columns, sizeof(char), len, fp); +} + +/* ---------------------------------------------------------------------- */ + +void DumpCustom::header_time_binary() +{ + char flag = time_flag ? 1 : 0; + fwrite(&flag, sizeof(char), 1, fp); + + if (time_flag) { + double t = compute_time(); + fwrite(&t, sizeof(double), 1, fp); + } +} + +/* ---------------------------------------------------------------------- */ + +void DumpCustom::header_format_binary() +{ + format_magic_string_binary(); + format_endian_binary(); + format_revision_binary(); +} + +/* ---------------------------------------------------------------------- */ + void DumpCustom::header_binary(bigint ndump) { + header_format_binary(); + fwrite(&update->ntimestep,sizeof(bigint),1,fp); fwrite(&ndump,sizeof(bigint),1,fp); fwrite(&domain->triclinic,sizeof(int),1,fp); @@ -394,6 +469,11 @@ void DumpCustom::header_binary(bigint ndump) fwrite(&boxzlo,sizeof(double),1,fp); fwrite(&boxzhi,sizeof(double),1,fp); fwrite(&size_one,sizeof(int),1,fp); + + header_unit_style_binary(); + header_time_binary(); + header_columns_binary(); + if (multiproc) fwrite(&nclusterprocs,sizeof(int),1,fp); else fwrite(&nprocs,sizeof(int),1,fp); } diff --git a/src/dump_custom.h b/src/dump_custom.h index 1420d69b9b..0f63eac8de 100644 --- a/src/dump_custom.h +++ b/src/dump_custom.h @@ -29,6 +29,10 @@ class DumpCustom : public Dump { DumpCustom(class LAMMPS *, int, char **); virtual ~DumpCustom(); + const char * MAGIC_STRING = "DUMPCUSTOM"; + const int FORMAT_REVISION = 0x0002; + const int ENDIAN = 0x0001; + protected: int nevery; // dump frequency for output int iregion; // -1 if no region, else which region @@ -107,6 +111,14 @@ class DumpCustom : public Dump { int add_custom(char *, int); virtual int modify_param(int, char **); + void header_format_binary(); + void header_unit_style_binary(); + void header_time_binary(); + void header_columns_binary(); + void format_magic_string_binary(); + void format_endian_binary(); + void format_revision_binary(); + typedef void (DumpCustom::*FnPtrHeader)(bigint); FnPtrHeader header_choice; // ptr to write header functions void header_binary(bigint); diff --git a/unittest/formats/CMakeLists.txt b/unittest/formats/CMakeLists.txt index df8ed31750..b31798aecf 100644 --- a/unittest/formats/CMakeLists.txt +++ b/unittest/formats/CMakeLists.txt @@ -36,4 +36,5 @@ set_tests_properties(DumpCustom PROPERTIES ENVIRONMENT "LAMMPS_POTENTIALS=${LAMM if (BUILD_TOOLS) set_tests_properties(DumpAtom PROPERTIES ENVIRONMENT "BINARY2TXT_BINARY=$") + set_tests_properties(DumpCustom PROPERTIES ENVIRONMENT "BINARY2TXT_BINARY=$") endif() diff --git a/unittest/formats/test_dump_custom.cpp b/unittest/formats/test_dump_custom.cpp index da700c7b8a..e4787acd7f 100644 --- a/unittest/formats/test_dump_custom.cpp +++ b/unittest/formats/test_dump_custom.cpp @@ -24,46 +24,110 @@ char * BINARY2TXT_BINARY = nullptr; class DumpCustomTest : public MeltTest { }; -TEST_F(DumpCustomTest, run0) +TEST_F(DumpCustomTest, run1) { - auto dump_file = "dump_custom_run0.melt"; + auto dump_file = "dump_custom_run1.melt"; if (!verbose) ::testing::internal::CaptureStdout(); command(fmt::format("dump id all custom 1 {} id type x y vx fx", dump_file)); - command("run 0"); + command("dump_modify id units yes"); + command("run 1"); if (!verbose) ::testing::internal::GetCapturedStdout(); ASSERT_FILE_EXISTS(dump_file); auto lines = read_lines(dump_file); - ASSERT_EQ(lines.size(), 41); - ASSERT_STREQ(lines[4].c_str(), "ITEM: BOX BOUNDS pp pp pp"); - ASSERT_EQ(utils::split_words(lines[5]).size(), 2); - ASSERT_STREQ(lines[8].c_str(), "ITEM: ATOMS id type x y vx fx"); - ASSERT_EQ(utils::split_words(lines[9]).size(), 6); + ASSERT_EQ(lines.size(), 84); + ASSERT_STREQ(lines[6].c_str(), "ITEM: BOX BOUNDS pp pp pp"); + ASSERT_EQ(utils::split_words(lines[7]).size(), 2); + ASSERT_STREQ(lines[10].c_str(), "ITEM: ATOMS id type x y vx fx"); + ASSERT_EQ(utils::split_words(lines[11]).size(), 6); delete_file(dump_file); } -TEST_F(DumpCustomTest, triclinic_run0) +TEST_F(DumpCustomTest, binary_run1) { - auto dump_file = "dump_custom_tri_run0.melt"; + auto text_file = "dump_custom_text_run1.melt"; + auto binary_file = "dump_custom_binary_run1.melt.bin"; + auto converted_file = fmt::format("{}.txt", binary_file); + + if(!BINARY2TXT_BINARY) GTEST_SKIP(); + + if (!verbose) ::testing::internal::CaptureStdout(); + command(fmt::format("dump id0 all custom 1 {} id type x y vx fx", text_file)); + command(fmt::format("dump id1 all custom 1 {} id type x y vx fx", binary_file)); + command("dump_modify id0 units yes"); + command("dump_modify id1 units yes"); + command("run 1"); + if (!verbose) ::testing::internal::GetCapturedStdout(); + + ASSERT_FILE_EXISTS(text_file); + ASSERT_FILE_EXISTS(binary_file); + + if (!verbose) ::testing::internal::CaptureStdout(); + std::string cmdline = fmt::format("{} {}", BINARY2TXT_BINARY, binary_file); + system(cmdline.c_str()); + if (!verbose) ::testing::internal::GetCapturedStdout(); + + ASSERT_FILE_EXISTS(converted_file); + ASSERT_FILE_EQUAL(text_file, converted_file); + delete_file(text_file); + delete_file(binary_file); + delete_file(converted_file); +} + +TEST_F(DumpCustomTest, triclinic_run1) +{ + auto dump_file = "dump_custom_tri_run1.melt"; if (!verbose) ::testing::internal::CaptureStdout(); command("change_box all triclinic"); command(fmt::format("dump id all custom 1 {} id type x y vx fx", dump_file)); - command("run 0"); + command("dump_modify id units yes"); + command("run 1"); if (!verbose) ::testing::internal::GetCapturedStdout(); ASSERT_FILE_EXISTS(dump_file); auto lines = read_lines(dump_file); - ASSERT_STREQ(lines[4].c_str(), "ITEM: BOX BOUNDS xy xz yz pp pp pp"); - ASSERT_EQ(utils::split_words(lines[5]).size(), 3); + ASSERT_STREQ(lines[6].c_str(), "ITEM: BOX BOUNDS xy xz yz pp pp pp"); + ASSERT_EQ(utils::split_words(lines[7]).size(), 3); - ASSERT_EQ(lines.size(), 41); + ASSERT_EQ(lines.size(), 84); delete_file(dump_file); } +TEST_F(DumpCustomTest, binary_triclinic_run1) +{ + auto text_file = "dump_custom_tri_text_run1.melt"; + auto binary_file = "dump_custom_tri_binary_run1.melt.bin"; + auto converted_file = fmt::format("{}.txt", binary_file); + + if(!BINARY2TXT_BINARY) GTEST_SKIP(); + + if (!verbose) ::testing::internal::CaptureStdout(); + command(fmt::format("dump id0 all custom 1 {} id type x y vx fx", text_file)); + command(fmt::format("dump id1 all custom 1 {} id type x y vx fx", binary_file)); + command("dump_modify id0 units yes"); + command("dump_modify id1 units yes"); + command("run 1"); + if (!verbose) ::testing::internal::GetCapturedStdout(); + + ASSERT_FILE_EXISTS(text_file); + ASSERT_FILE_EXISTS(binary_file); + + if (!verbose) ::testing::internal::CaptureStdout(); + std::string cmdline = fmt::format("{} {}", BINARY2TXT_BINARY, binary_file); + system(cmdline.c_str()); + if (!verbose) ::testing::internal::GetCapturedStdout(); + + ASSERT_FILE_EXISTS(converted_file); + ASSERT_FILE_EQUAL(text_file, converted_file); + delete_file(text_file); + delete_file(binary_file); + delete_file(converted_file); +} + int main(int argc, char **argv) {