物理模拟数值数据数据库

Database for numerical data from physics simulation

我从事理论物理学工作,并且进行了大量计算机模拟。我职责的一个重要部分是分析结果。我进行模拟并将数值结果存储在一个名称简单的文件中。通常我有很多名称非常相似的数据文件,过了一会儿我不记得文件对应的参数类型。我在想,也许存在一种更好的方法来存储模拟的数值结果,例如一些数据库(SQL、MongoDB 等),我可以在其中放置一些关于程序参数、名称、日期等的注释 - 一种带有数字数据的库。我只是把所有东西都组织得井井有条。你知道这样的事情吗?您如何存储来自计算机模拟的数值数据?

更多详情

典型的过程如下所示。假设我们要模拟三体问题的时间演化。我们有三个质量不同的物体与牛顿力相互作用。我想测试这些物体如何在 space 中移动,具体取决于:相对质量值、初始位置 - 6 个参数。我 运行 模拟一个参数选择并将其保存在文件中: three_body_m1=0p1_m2=0p3_(the rest).dat - 所有双精度总共 1+3*3 (3d ) 一个文件中的数据列。然后我用午餐 gnuplot、python 等并将它们可视化。原则上不同模拟的数据之间没有关系,但我可以用它们来制作比较图。

在相同的 nodejs 上下文中,你可以,

  • 使用 socket.io-stream + fs 模块将大 xyz 数据文件流式传输到服务器,并使用 mongodb 模块将文件名+参数保存到数据库。(最多 1 页编码但更多的是复杂的服务器对话)

  • 如果数据在内存中,如果你不需要立即保存,你可以使用redis模块轻松地将所有内容发送到服务器缓存(作为键值对,如data->xyzData and parameters->simulationParameters and user->name_surname) 并从中高速读取。如果您需要服务器中其他进程的数据作为文件,您可以改为使用 ramdisk 并将大部分 RAM 带宽用作文件缓存。(当然需要更多 ram 但速度很快)

  • mongodb 保存数百万粒子 xyz 数据的速度很慢(即使进行了优化),但对于参数保存和共享来说是最简单和最快的安装。

全部使用会更好。

  • 保存:使用 socket.io-stream 和 fs 将文件流式传输到物理磁盘。发送参数到mongodb.
  • 加载:检查redis是否有用户注册,检查数据是否在缓存中,如果有则获取,如果没有则从物理磁盘流并同时保存一部分到redis。
  • 编辑:检查缓存是否存在,如果存在则进行编辑。另一个服务器端进程可以从该缓存更新物理磁盘,如果没有则直接更新物理磁盘。

通信方案可以是:

  • 如果有任何未决的 writes/reads/edits,数据服务器会与缓存服务器通信,从那里使用作业。

  • 计算服务器与缓存服务器对话以生成 read/write/edit 作业或消耗计算作业。

  • 客户端可以只读缓存服务器。

  • 管理员还可以放置自己的数据或生成计算作业或阅读资料。

  • 计算服务器、数据服务器和缓存服务器可以很容易地在同一台计算机上或移动到其他计算机上,这要归功于 nodejs 的强大和它的无数模块,如 redis、socket.io-stream、 fs, ejs, express(以客户为例)等

  • 缓存服务器可以将一些数据卸载到另一个缓存服务器并对其进行重定向(或将数据映射到它)

  • 一个缓存服务器可以同时与N个数据服务器和M个计算服务器通信,只要RAM保持不变。

你的网速很慢?只需 3-5 行额外代码(两端),您就可以使用 gzip 模块即时压缩数据

你没钱?

  • Nodejs 在 raspberry pi 上工作(可能作为数据服务器?)
  • Nvidia GTX660 可以与 Intel galileo(计算服务器?)一起工作,使用 nodejs 和一些用于 opencl 的额外本机模块(可能难以实现)(连接(和供电)gpu 和 galileo 可能并不容易,但应该比 fp32 数字运算的 raspberry pi 板集群快得多)
  • 绕过缓存,RAM 现在很贵。

 data server cluster
               \
                \
                 \                        client
                  \             client    /
                   \            /        /
                    \          /        /
               mainframe cache and database server ----- compute cluster
                          |                   \
                          |                    \
                    support cache server        admin

将一些文件发送到另一台计算机(或同一台计算机)的一个非常简单的示例:

var pipeline_n = 8;


var fs = require("fs");

// server part accepting files
{
    var io = require('socket.io').listen(80);
    var ss = require('socket.io-stream');
    var path = require('path');
    var ctr = 0;
    var ctr2 = 0;
    io.of('/user').on('connection', function (socket) {

        var z1 = new Date();

        for (var i = 0; i < pipeline_n; i++) {
            ss(socket).on('data'+i.toString(), function (stream, data) {
                var t1 = new Date();
                stream.pipe(fs.createWriteStream("m://bench_server" + ctr + ".txt"));
                ctr++;
                stream.on("finish", function (p) {
                    var len = stream._readableState.pipes.bytesWritten;
                    var t2 = new Date();


                    ctr2++;
                    if (ctr2 == pipeline_n) {
                        var z2 = new Date();
                        console.log(len * pipeline_n);
                        console.log((z2 - z1));
                        console.log("throughput: " + ((len * pipeline_n) / ((z2 - z1)/1000.0))/(1024*1024)+" MB/s");
                    }
                });

            });
        }

    });
}


//client or another server part sending a file
//(you can change it to do parts of same file instead of same file n times),
//just a dummy file sending code to stress other server

for (var i = 0; i < pipeline_n; i++)
{
    var io = require('socket.io-client');
    var ss = require('socket.io-stream');

    var socket = io.connect('http://127.0.0.1/user');
    var stream = ss.createStream();
    var filename = 'm://bench.txt'; // ramdrive or cluster of hdd raid

    ss(socket).emit('data'+i.toString(), stream, { name: filename });
    fs.createReadStream(filename).pipe(stream);

}

这里是测试 mongodb 的插入与批量插入性能(这可能是一种错误的基准测试方式,但很简单,只需取消注释 - 在您想要进行基准测试的部分)

var mongodb = require('mongodb');
var client = mongodb.MongoClient;
var url = 'mongodb://localhost:2019/evdb2';
client.connect(url, function (err, db) {
    if (err) {
        console.log('fail:', err);
    } else {
        console.log('success:', url);
        var collection = db.collection('tablo');

        var bulk = collection.initializeUnorderedBulkOp();


        db.close();

        //benchmark insert
        //var t = 0;
        //t = new Date();
        //var ctr = 0;
        //for (var i = 0; i < 1024 * 64; i++)
        //{
        //    collection.insert({ x: i + 1, y: i, z: i * 10 }, function (e, r) {
        //        ctr++;
        //        if (ctr == 1024 * 64)
        //        {
        //            var t2 = 0;
        //            db.close();
        //            t2 = new Date();
        //            console.log("insert-64k: " + 1000.0 / ((t2.getTime() - t.getTime()) / (1024 * 64)) + " insert/s");
        //        }
        //    });
        //}


        // benchmark bulk insert
        //var t3 = new Date();
        //for (var i = 0; i < 1024 * 64; i++)
        //{
        //    bulk.insert({ x: i + 1, y: i, z: i * 10 });
        //}
        //bulk.execute();
        //var t4 = new Date();
        //console.log("bulk-insert-64k: " + 1000.0/((t4.getTime() - t3.getTime()) / (1024 * 64)) + " insert/s");
        //           db.close();

    }
});

确保在此之前设置 mongodb 和/或 redis 服务器。还有 "npm install module_name" 来自 nodejs 命令提示符的必要模块。