2D向量数组填充为零而不是双精度值

时间:2019-05-04 21:42:51

标签: c++

我正在编写一个程序,该程序从输入文件中读取有关分子的信息(电荷,多重性,原子类型及其坐标),但是由于某种原因,二维矢量数组被零填充,并找到一个不存在的原子进行协调也是零。我不知道如何正确调试它,所以我无法跟踪问题。

#include <iostream>
#include <cstdlib>
#include <string>
#include <fstream>
#include <cassert>
#include <vector>

int main(int argc, char* argv[])
{
   if (argc > 1)
   {

      std::cout << "The input file is: " << argv[1] << std::endl;

   } else
           {
             std::cout << "No arguments" << std::endl;
             return 1;
           }

   const char *filename = argv[1];
   std::ifstream inputfile(filename);
   assert(inputfile.good());
   int charge, multiplicity;
   inputfile >> charge >> multiplicity;

   std::cout << charge << " " << multiplicity << std::endl;

   int natom;

   std::vector<std::string> atomSymbol;
   std::vector< std::vector<double> > position;

   for (int i = 0; !inputfile.eof(); i++) {

   std::string bufferAtomicSymbol;
   double bufferPositionX;
   double bufferPositionY;
   double bufferPositionZ;

   std::vector<double> bufferPosition(3);

   inputfile >> bufferAtomicSymbol >> bufferPositionX >> bufferPositionY >> bufferPositionZ; 

   atomSymbol.push_back(bufferAtomicSymbol);
   bufferPosition.push_back(bufferPositionX);
   bufferPosition.push_back(bufferPositionY);
   bufferPosition.push_back(bufferPositionZ);

   position.push_back(bufferPosition);

   }

   inputfile.close();
   natom = position.size();

   std::cout << "There are " << natom << " atoms" << std::endl;

   for (int i = 0; i < natom; i++)
       std::cout << atomSymbol[i] << " " << position[i][0] << " " << position[i][1] << " " << position[i][2] << std::endl;

   return 0;
   }

输入文件示例:

0 1
C          1.11988       -0.11356       -0.04893
C         -0.22149        0.53742        0.15390
N         -1.36703       -0.23693       -0.04570
O         -0.39583        1.70537        0.48392
H          1.93813        0.59458        0.13709
H          1.23188       -0.48457       -1.07645
H          1.25795       -0.96373        0.63239
H         -2.27205        0.14808        0.07622
H         -1.29145       -1.18667       -0.31244

程序输出:

The input file is: acetamide.xyz
0 1
There are 10 atoms
C 0 0 0
C 0 0 0
N 0 0 0
O 0 0 0
H 0 0 0
H 0 0 0
H 0 0 0
H 0 0 0
H 0 0 0
 0 0 0

1 个答案:

答案 0 :(得分:1)

您有两个主要问题困扰着您尝试从数据文件中成功读取数据,一个是特定问题,另一个是更笼统的问题,但这两个问题都同样致命。

通过阅读Why !.eof() inside a loop condition is always wrong.可以解决阅读中的技术问题。您面临的同样重要的更普遍的普遍问题是,您试图将胶带和捆扎线捆扎在一起的vectorsstringsdoubles的清单庞大。当您使用多余的或不合适的容器使数据处理过于复杂时,试图使它们协同工作就像将牙膏放回试管中一样-不会起作用。...

花一点时间,整理一下每个数据块需要存储的内容,然后创建一个保存该数据的数据结构。可以使用一些临时变量来方便地读取数据,但是数据的最终存储应该简单明了,并且要尽可能地简单。

在您的情况下,您将原子符号存储为string和位置的三个double值。您的基本数据结构应该能够将所有三个对象捕获为一个对象。尽管有两种选择,但是用于在不同类型的数据之间进行协调的普通struct可以正常工作。然后,您只需创建 struct向量作为最终存储解决方案,以允许访问数据。

按照要求的简单性,您可以使用包含struct和三个string值的double。例如:

struct atom {
    std::string sym;
    double x, y, z;
};

这就是捕获符号和位置坐标所需的全部。您只需声明一个 atom向量作为最终存储解决方案,例如

    std::vector<atom> atoms;            /* your final storage container */

整个代码中正在运行的主题将引发未定义行为,但该主题无法验证每个输入。如果您只是从流中读取而没有 validation (读取是否成功),那么您只是在玩Russian-Roulette。如果读取失败,并且您只是盲目地使用未初始化的变量继续前进,则假定已正确填充数据,结束了游戏。

因此请验证每次读取。例如,阅读chargemultiplicity,您可以执行以下操作:

    if (!(fs >> charge >> multiplicity)) {  /* validate EVERY input */
        std::cerr << "error: invalid format: charge, multiplicity\n";
        return 1;
    }

注意:,我已经缩短了您的变量名,例如inputfile现在是fs,键入不适合)

要从文件的每个后续行中读取每个原子,可以执行以下操作:

    /* read each remaining line until you run out */
    while (fs >> atmSymbol >> bposX >> bposY >> bposZ) {
        /* add the values read to your temporary struct */
        atom tmp = { atmSymbol, bposX, bposY, bposZ };
        atoms.push_back(tmp);   /* push tmp struct onto storage vector */
    }

关键是验证每次读取的成功或失败,以便您知道您正在处理代码中的有效数据。

在一个简短的示例中将其余部分放在一起以读取数据文件,您可以执行以下操作:

#include <iostream>
#include <iomanip>
#include <fstream>
#include <array>
#include <string>
#include <vector>

struct atom {
    std::string sym;
    double x, y, z;
};

int main (int argc, char *argv[]) {

    if (argc < 2) { /* validate at least one argument given for filename */
        std::cout << "error: insuffient input.\n"
                    "usage: " << argv[0] << " <fn>\n";
        return 1;
    }
    std::cout << "The input file is: " << argv[1] << '\n';

    std::ifstream fs (argv[1]);         /* file stream, just use argv[1] */
    int charge, multiplicity, natom;    /* temporary variables for filling */
    double bposX, bposY, bposZ;
    std::string atmSymbol;
    std::vector<atom> atoms;            /* your final storage container */

    if (!(fs >> charge >> multiplicity)) {  /* validate EVERY input */
        std::cerr << "error: invalid format: charge, multiplicity\n";
        return 1;
    }
    /* read each remaining line until you run out */
    while (fs >> atmSymbol >> bposX >> bposY >> bposZ) {
        /* add the values read to your temporary struct */
        atom tmp = { atmSymbol, bposX, bposY, bposZ };
        atoms.push_back(tmp);   /* push tmp struct onto storage vector */
    }
    fs.close(); /* close stream -- you are done reading */

    natom = atoms.size();   /* get an output size */
    std::cout << "\nThere are " << natom << " atoms.\n\n";

    for (auto& a : atoms) {         /* loop over each atom in vector */
        std::cout << a.sym          /* output atomic symbol */
                << " " << std::setw(8) << a.x   /* each coordinate, and */
                << " " << std::setw(8) << a.y
                << " " << std::setw(8) << a.z << '\n';/* tidy up with \n */
    }
}

使用/输出示例

$ ./bin/atoms_read dat/atoms.txt
The input file is: dat/atoms.txt

There are 9 atoms.

C   1.11988 -0.11356 -0.04893
C  -0.22149  0.53742   0.1539
N  -1.36703 -0.23693  -0.0457
O  -0.39583  1.70537  0.48392
H   1.93813  0.59458  0.13709
H   1.23188 -0.48457 -1.07645
H   1.25795 -0.96373  0.63239
H  -2.27205  0.14808  0.07622
H  -1.29145 -1.18667 -0.31244

仔细检查一下,如果还有其他问题,请告诉我。

根据请求处理文件中的空行进行更新

如果要在数据文件中读取其他由空行分隔的原子块,您要做的就是稍微重新排列读取范围,以使用getline一次读取文件中的一行。然后,从该行创建一个stringstream并从字符串流中读取,就像我们最初从文件中读取的一样。如果您可以有效地从字符串流中读取原子符号和位置坐标,那么您有一条有效的线。

使用getline进行快速编辑并删除不再需要的临时变量(我们现在可以直接读取到临时结构中),您可以这样做:

    std::ifstream fs (argv[1]);         /* file stream, just use argv[1] */
    int charge, multiplicity, natom;    /* temporary variables for filling */
    std::string line;
    std::vector<atom> atoms;            /* your final storage container */

    if (!(fs >> charge >> multiplicity)) {  /* validate EVERY input */
        std::cerr << "error: invalid format: charge, multiplicity\n";
        return 1;
    }
    /* read each remaining line until you run out with getline */
    while (getline (fs, line)) {
        std::stringstream ss (line);    /* create stringstream from line */
        atom tmp;                       /* declare temporary struct */
        /* read from stringstream into temporary struct */
        if (ss >> tmp.sym >> tmp.x >> tmp.y >> tmp.z)
            atoms.push_back(tmp);  /* push_back atmp struct on success */
    }
    fs.close(); /* close stream -- you are done reading */

现在,从第二行开始,代码将把与您的行格式匹配的所有原子数据读入atoms向量中,而与文件中的空白行或其他不合格行无关。