/* ---------------------------------------------------------------------- This is the ██╗ ██╗ ██████╗ ██████╗ ██████╗ ██╗ ██╗████████╗███████╗ ██║ ██║██╔════╝ ██╔════╝ ██╔════╝ ██║ ██║╚══██╔══╝██╔════╝ ██║ ██║██║ ███╗██║ ███╗██║ ███╗███████║ ██║ ███████╗ ██║ ██║██║ ██║██║ ██║██║ ██║██╔══██║ ██║ ╚════██║ ███████╗██║╚██████╔╝╚██████╔╝╚██████╔╝██║ ██║ ██║ ███████║ ╚══════╝╚═╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝® DEM simulation engine, released by DCS Computing Gmbh, Linz, Austria http://www.dcs-computing.com, office@dcs-computing.com LIGGGHTS® is part of CFDEM®project: http://www.liggghts.com | http://www.cfdem.com Core developer and main author: Christoph Kloss, christoph.kloss@dcs-computing.com LIGGGHTS® is open-source, distributed under the terms of the GNU Public License, version 2 or later. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. You should have received a copy of the GNU General Public License along with LIGGGHTS®. If not, see http://www.gnu.org/licenses . See also top-level README and LICENSE files. LIGGGHTS® and CFDEM® are registered trade marks of DCS Computing GmbH, the producer of the LIGGGHTS® software and the CFDEM®coupling software See http://www.cfdem.com/terms-trademark-policy for details. ------------------------------------------------------------------------- Contributing author and copyright for this file: (if no contributing author is listed, this file has been contributed by the core developer) Arno Mayrhofer (DCS Computing GmbH, Linz) Copyright 2016- DCS Computing GmbH, Linz ------------------------------------------------------------------------- */ #ifdef LAMMPS_VTK #include #include "math_extra_liggghts.h" #include #include #include #include "dump_custom_vtm.h" #ifdef CONVEX_ACTIVE_FLAG #include "atom_vec_convexhull.h" #endif #include "atom.h" #include "compute.h" #include "domain.h" #include "error.h" #include "fix.h" #include "force.h" #include "group.h" #include "input.h" #include "memory.h" #include "modify.h" #include "output.h" #include "region.h" #include "update.h" #include "variable.h" #include #include #include #include #ifndef VTK_MAJOR_VERSION #include #endif #include #include #include #include #include #ifdef _WIN32 #include "dirent.h" #else #include #endif // For compatibility with new VTK generic data arrays (VTK >= 7.0) #ifdef vtkGenericDataArray_h #define InsertNextTupleValue InsertNextTypedTuple #endif using namespace LAMMPS_NS; // customize by // * adding an enum constant (add vector components in consecutive order) // * adding a pack_*(int) function for the value // * adjusting parse_fields function to add the pack_* function to pack_choice // (in case of vectors, adjust identify_vectors as well) // * adjusting thresh part in modify_param and count functions /* ---------------------------------------------------------------------- */ DumpCustomVTM::DumpCustomVTM(LAMMPS *lmp, int narg, char **arg) : Dump(lmp, narg, arg), DumpVTK(lmp), nevery(0), filecurrent(NULL), parallelfilecurrent(NULL), multiname_ex(NULL), dumpParticle(NULL), dumpMesh(NULL), write_pv_config(false), write_pvd_file(false), pvd_ntimesteps(0) { if (narg <= 7) error->all(FLERR,"dump custom/vtm lacks arguments"); clearstep = 1; nevery = force->inumeric(FLERR,arg[3]); // TODO Remove the following lines // Single proc writing due to a paraview bug if (me != 0) filewriter = 0; fileproc = 0; multiproc = 0; nclusterprocs = nprocs; // TODO end remove if (!vtkMultiProcessController::GetGlobalController()) { vtkMPIController *vtkController = vtkMPIController::New(); vtkController->Initialize(); vtkMultiProcessController::SetGlobalController(vtkController); } vtkMPIController * controller = getLocalController(); std::list allowed_extensions; allowed_extensions.push_back(VTK_FILE_FORMATS::PVTM); DumpVTK::identify_file_type(filename, allowed_extensions, style, multiproc, nclusterprocs, filewriter, fileproc, world, clustercomm); bool hasargs = true; int iarg = 5; // all keywords that start a new dump class keyword_list.push_back("particle_properties"); keyword_list.push_back("meshes"); keyword_list.push_back("local_gran"); keyword_list.push_back("write_pv_config"); keyword_list.push_back("write_pvd_file"); // loop over all arguments while (iarg < narg && hasargs) { hasargs = false; if (strcmp(arg[iarg], "particle_properties") == 0) { if (!dumpParticle) dumpParticle = new DumpParticle(lmp, igroup, nclusterprocs, multiproc, nevery, filewriter, fileproc); else error->all(FLERR, "Internal error (multiple particle_properties keywords?)"); iarg += dumpParticle->parse_parameters(narg-iarg, &(arg[iarg]), false, keyword_list); hasargs = true; } else if (strcmp(arg[iarg], "meshes") == 0) { if (!dumpMesh) dumpMesh = new DumpMesh(lmp, nclusterprocs, multiproc, filewriter, fileproc, controller); else error->all(FLERR, "Internal error (multiple meshes keywords?)"); iarg += dumpMesh->parse_parameters(narg-iarg, &(arg[iarg]), keyword_list); hasargs = true; } else if (strcmp(arg[iarg], "local_gran") == 0) { dumpLocalGranList.push_back(DumpLocalGran(lmp, igroup, nclusterprocs, multiproc, nevery, filewriter, fileproc)); iarg += dumpLocalGranList.back().parse_parameters(narg-iarg, &(arg[iarg]), false, keyword_list); hasargs = true; } else if (strcmp(arg[iarg], "write_pv_config") == 0) { if (++iarg >= narg) error->all(FLERR, "write_pv_config in dump custom/vtm requires one argument"); if (strcmp(arg[iarg], "yes") == 0) write_pv_config = true; else if (strcmp(arg[iarg], "no") == 0) write_pv_config = false; else error->all(FLERR, "write_pv_config in dump custom/vtm requires either \"yes\" or \"no\" as argument"); iarg++; hasargs = true; } else if (strcmp(arg[iarg], "write_pvd_file") == 0) { if (++iarg >= narg) error->all(FLERR, "write_pvd_file in dump custom/vtm requires one argument"); if (strcmp(arg[iarg], "yes") == 0) write_pvd_file = true; else if (strcmp(arg[iarg], "no") == 0) write_pvd_file = false; else error->all(FLERR, "write_pvd_file in dump custom/vtm requires either \"yes\" or \"no\" as argument"); iarg++; hasargs = true; } else { error->all(FLERR, "Unknown keyword in dump custom/vtm"); } } if (iarg < narg) error->all(FLERR,"Invalid attribute in dump custom/vtm command"); for (int i = 0; i < output->ndump; i++) { if (strcmp(output->dump[i]->style, "custom/vtm") == 0) error->all(FLERR, "Only one dump custom/vtm is allowed"); } if (write_pvd_file && comm->me == 0) { std::string fname(filename); DIR *dir; struct dirent *ent; std::size_t found = fname.find_last_of("/\\"); std::string dirname = ""; if (found != std::string::npos) dirname = fname.substr(0,found+1); //while (true) //{ // found = dirname.find("/"); // if (found == std::string::npos) // break; // dirname.replace(found, 1, "\\"); //} if ((dir = opendir (dirname.c_str())) != NULL) { std::string basename = fname.substr(found+1); std::size_t last_spec_char = basename.find_last_of("*%"); std::size_t first_spec_char = basename.find_first_of("*%"); std::string prefix = basename.substr(0, first_spec_char); std::string postfix = basename.substr(last_spec_char+1); std::size_t star_char = basename.find("*"); if (star_char == std::string::npos) error->one(FLERR, "Could not find * in filename"); std::string starpostfix = basename.substr(star_char+1); // print all the files and directories within directory while ((ent = readdir (dir)) != NULL) { std::string curfile = std::string(ent->d_name); if (curfile.find(prefix) != 0) continue; if (curfile.find(postfix) != curfile.length() - postfix.length()) continue; std::size_t end_nr = curfile.find(starpostfix); std::string nr = curfile.substr(star_char, end_nr - star_char); int ts = atoi(nr.c_str()); // add each entry to a pair list ts_files.push_back(std::pair(ts, curfile)); } closedir (dir); // sort the pair list by the int std::sort(ts_files.begin(), ts_files.end()); // open pvd file std::fstream pvdFile; std::string pvdFname = dirname; pvdFname.append("liggghts_simulation.pvd"); pvdFile.open(pvdFname.c_str(), std::fstream::out); // write header pvdFile << "" << endl; pvdFile << "" << endl; // write pvd file for (pvd_ntimesteps = 0; pvd_ntimesteps < ts_files.size(); pvd_ntimesteps++) { if (ts_files[pvd_ntimesteps].first >= update->ntimestep) break; pvdFile << "" << endl; } // delete unused entries if (pvd_ntimesteps < ts_files.size()) ts_files.erase(ts_files.begin()+pvd_ntimesteps, ts_files.end()); // write footer pvdFile << "" << endl; pvdFile << "" << endl; // close pvd file pvdFile.close(); } else { /* could not open directory */ error->one(FLERR, "Could not open directory in custom/vtm"); } } } /* ---------------------------------------------------------------------- */ DumpCustomVTM::~DumpCustomVTM() { delete [] filecurrent; delete [] parallelfilecurrent; delete [] multiname_ex; delete dumpParticle; if (dumpMesh) delete dumpMesh; dumpLocalGranList.clear(); } /* ---------------------------------------------------------------------- */ void DumpCustomVTM::init_style() { dumpParticle->init_style(); if (dumpMesh) dumpMesh->init_style(); std::list::iterator it; for (it = dumpLocalGranList.begin(); it != dumpLocalGranList.end(); it++) it->init_style(); } /* ---------------------------------------------------------------------- */ void DumpCustomVTM::write_header(bigint /*ndump*/) { } /* ---------------------------------------------------------------------- */ int DumpCustomVTM::count() { return 0; } /* ---------------------------------------------------------------------- */ void DumpCustomVTM::setFileCurrent() { DumpVTK::setFileCurrent(filecurrent, filename, multifile, padflag); } /* ---------------------------------------------------------------------- */ void DumpCustomVTM::write() { setFileCurrent(); // multi block data set that will contain everything vtkSmartPointer mbSet = vtkSmartPointer::New(); // mesh data if (dumpMesh) dumpMesh->prepare_mbSet(mbSet); std::list::iterator it; for (it = dumpLocalGranList.begin(); it != dumpLocalGranList.end(); it++) it->prepare_mbSet(mbSet, true); // particle & domain data dumpParticle->prepare_mbSet(mbSet); if (!filewriter) return; DumpVTK::write_vtm(mbSet, filecurrent); // write out paraview configuration file for python script (paraview_generic_display.py) if (write_pv_config && comm->me == 0) { std::fstream configFile; std::string path = std::string(filecurrent); std::size_t endpath = path.find_last_of("/\\"); std::string config_fname = "pv_config.txt"; if (endpath != std::string::npos) config_fname = path.substr(0,endpath+1).append(config_fname); configFile.open(config_fname.c_str(), std::fstream::out); int nlocalgran = dumpLocalGranList.size(); int nmeshes = mbSet->GetNumberOfBlocks() - nlocalgran - 2; // -2 = particles & domain configFile << "# This is a config file for paraview_generic_display.py" << endl; configFile << "# This file was created automatically using LIGGGHTS and dump custom/vtm" << endl; configFile << "########################" << endl; configFile << "# DO NOT EDIT THIS FILE" << endl; configFile << "########################" << endl; configFile << "nmeshes: " << nmeshes << endl; configFile << "nlocalgran: " << nlocalgran << endl; if (domain->triclinic) { configFile << "bbxmin: " << domain->boxlo_bound[0] << endl; configFile << "bbxmax: " << domain->boxhi_bound[0] << endl; configFile << "bbymin: " << domain->boxlo_bound[1] << endl; configFile << "bbymax: " << domain->boxhi_bound[1] << endl; configFile << "bbzmin: " << domain->boxlo_bound[2] << endl; configFile << "bbzmax: " << domain->boxhi_bound[2] << endl; } else { configFile << "bbxmin: " << domain->boxlo[0] << endl; configFile << "bbxmax: " << domain->boxhi[0] << endl; configFile << "bbymin: " << domain->boxlo[1] << endl; configFile << "bbymax: " << domain->boxhi[1] << endl; configFile << "bbzmin: " << domain->boxlo[2] << endl; configFile << "bbzmax: " << domain->boxhi[2] << endl; } configFile.close(); } if (write_pvd_file && comm->me == 0) { std::string dirname = ""; std::string fname(filename); std::size_t found = fname.find_last_of("/\\"); if (found != std::string::npos) dirname = fname.substr(0,found+1); // add a new entry to a pair list std::string curfile = filecurrent; found = curfile.find_last_of("/\\"); if (found != std::string::npos) curfile = curfile.substr(found+1); ts_files.push_back(std::pair(update->ntimestep, curfile)); // open pvd file std::fstream pvdFile; std::string pvdFname = dirname; pvdFname.append("liggghts_simulation.pvd"); pvdFile.open(pvdFname.c_str(), std::fstream::out); // write header pvdFile << "" << endl; pvdFile << "" << endl; // write pvd file for (unsigned int i = 0; i < ts_files.size(); i++) { pvdFile << "" << endl; } // write footer pvdFile << "" << endl; pvdFile << "" << endl; // close pvd file pvdFile.close(); pvd_ntimesteps++; } } /* ---------------------------------------------------------------------- */ int DumpCustomVTM::modify_param(int narg, char **arg) { const int mvtk = DumpVTK::modify_param(narg, arg); if (mvtk > 0) return mvtk; return dumpParticle->modify_param(narg, arg); } /* ---------------------------------------------------------------------- return # of bytes of allocated memory in buf, choose, variable arrays ------------------------------------------------------------------------- */ bigint DumpCustomVTM::memory_usage() { bigint bytes = Dump::memory_usage(); bytes += dumpParticle->memory_usage(); if (dumpMesh) bytes += dumpMesh->memory_usage(); std::list::iterator it; for (it = dumpLocalGranList.begin(); it != dumpLocalGranList.end(); it++) bytes += it->memory_usage(); return bytes; } #endif