Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#8376 - EnergyPlus with option --expandobjects set fails when working directory is not on the same device as the output directory (on Unix) #8410

Merged
merged 9 commits into from
Feb 11, 2021
105 changes: 52 additions & 53 deletions src/EnergyPlus/CommandLineInterface.cc
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ namespace EnergyPlus {
namespace CommandLineInterface {

using namespace DataStringGlobals;
using namespace FileSystem;
using namespace ez;

int ProcessArgs(EnergyPlusData &state, int argc, const char *argv[])
Expand Down Expand Up @@ -169,7 +168,7 @@ namespace CommandLineInterface {
opt.getUsage(usage);

// Set path of EnergyPlus program path
exeDirectory = getParentDirectoryPath(getAbsolutePath(getProgramPath()));
exeDirectory = FileSystem::getParentDirectoryPath(FileSystem::getAbsolutePath(FileSystem::getProgramPath()));

opt.get("-w")->getString(state.files.inputWeatherFileName.fileName);

Expand Down Expand Up @@ -209,10 +208,10 @@ namespace CommandLineInterface {
if (opt.lastArgs.size() == 0) inputFileName = "in.idf";

// Convert all paths to native paths
makeNativePath(inputFileName);
makeNativePath(state.files.inputWeatherFileName.fileName);
makeNativePath(inputIddFileName);
makeNativePath(outDirPathName);
FileSystem::makeNativePath(inputFileName);
FileSystem::makeNativePath(state.files.inputWeatherFileName.fileName);
FileSystem::makeNativePath(inputIddFileName);
FileSystem::makeNativePath(outDirPathName);

std::vector<std::string> badOptions;
if (opt.lastArgs.size() > 1u) {
Expand All @@ -238,10 +237,10 @@ namespace CommandLineInterface {
}
}

inputFileNameOnly = removeFileExtension(getFileName(inputFileName));
inputDirPathName = getParentDirectoryPath(inputFileName);
inputFileNameOnly = FileSystem::removeFileExtension(FileSystem::getFileName(inputFileName));
inputDirPathName = FileSystem::getParentDirectoryPath(inputFileName);

auto inputFileExt = getFileExtension(inputFileName);
auto inputFileExt = FileSystem::getFileExtension(inputFileName);
std::transform(inputFileExt.begin(), inputFileExt.end(), inputFileExt.begin(), ::toupper);

// TODO: figure out better logic for determining input file type
Expand Down Expand Up @@ -270,7 +269,7 @@ namespace CommandLineInterface {
exit(EXIT_FAILURE);
}

std::string weatherFilePathWithoutExtension = removeFileExtension(state.files.inputWeatherFileName.fileName);
std::string weatherFilePathWithoutExtension = FileSystem::removeFileExtension(state.files.inputWeatherFileName.fileName);

bool runExpandObjects(false);
bool runEPMacro(false);
Expand All @@ -286,7 +285,7 @@ namespace CommandLineInterface {
}

// Create directory if it doesn't already exist
makeDirectory(outDirPathName);
FileSystem::makeDirectory(outDirPathName);
}

outputDirPathName = outDirPathName;
Expand All @@ -296,7 +295,7 @@ namespace CommandLineInterface {
if (opt.isSet("-p")) {
std::string prefixOutName;
opt.get("-p")->getString(prefixOutName);
makeNativePath(prefixOutName);
FileSystem::makeNativePath(prefixOutName);
outputFilePrefix = outDirPathName + prefixOutName;
} else {
outputFilePrefix = outDirPathName + "eplus";
Expand Down Expand Up @@ -501,7 +500,7 @@ namespace CommandLineInterface {
// Read path from INI file if it exists

// Check for IDD and IDF files
if (fileExists(state.files.iniFile.fileName)) {
if (FileSystem::fileExists(state.files.iniFile.fileName)) {
auto iniFile = state.files.iniFile.try_open();
if (!iniFile.good()) {
DisplayString(state, "ERROR: Could not open file " + iniFile.fileName + " for input (read).");
Expand All @@ -522,15 +521,15 @@ namespace CommandLineInterface {
}

// Check if specified files exist
if (!fileExists(inputFileName)) {
DisplayString(state, "ERROR: Could not find input data file: " + getAbsolutePath(inputFileName) + ".");
if (!FileSystem::fileExists(inputFileName)) {
DisplayString(state, "ERROR: Could not find input data file: " + FileSystem::getAbsolutePath(inputFileName) + ".");
DisplayString(state, errorFollowUp);
exit(EXIT_FAILURE);
}

if (opt.isSet("-w") && !state.dataGlobal->DDOnlySimulation) {
if (!fileExists(state.files.inputWeatherFileName.fileName)) {
DisplayString(state, "ERROR: Could not find weather file: " + getAbsolutePath(state.files.inputWeatherFileName.fileName) + ".");
if (!FileSystem::fileExists(state.files.inputWeatherFileName.fileName)) {
DisplayString(state, "ERROR: Could not find weather file: " + FileSystem::getAbsolutePath(state.files.inputWeatherFileName.fileName) + ".");
DisplayString(state, errorFollowUp);
exit(EXIT_FAILURE);
}
Expand All @@ -540,49 +539,49 @@ namespace CommandLineInterface {

// Preprocessors (These will likely move to a new file)
if (runEPMacro) {
std::string epMacroPath = exeDirectory + "EPMacro" + exeExtension;
if (!fileExists(epMacroPath)) {
DisplayString(state, "ERROR: Could not find EPMacro executable: " + getAbsolutePath(epMacroPath) + ".");
std::string epMacroPath = exeDirectory + "EPMacro" + FileSystem::exeExtension;
if (!FileSystem::fileExists(epMacroPath)) {
DisplayString(state, "ERROR: Could not find EPMacro executable: " + FileSystem::getAbsolutePath(epMacroPath) + ".");
exit(EXIT_FAILURE);
}
std::string epMacroCommand = "\"" + epMacroPath + "\"";
bool inputFileNamedIn = (getAbsolutePath(inputFileName) == getAbsolutePath("in.imf"));
bool inputFileNamedIn = (FileSystem::getAbsolutePath(inputFileName) == FileSystem::getAbsolutePath("in.imf"));

if (!inputFileNamedIn) linkFile(inputFileName.c_str(), "in.imf");
if (!inputFileNamedIn) FileSystem::linkFile(inputFileName.c_str(), "in.imf");
DisplayString(state, "Running EPMacro...");
systemCall(epMacroCommand);
if (!inputFileNamedIn) removeFile("in.imf");
moveFile("audit.out", outputEpmdetFileName);
moveFile("out.idf", outputEpmidfFileName);
FileSystem::systemCall(epMacroCommand);
if (!inputFileNamedIn) FileSystem::removeFile("in.imf");
FileSystem::moveFile("audit.out", outputEpmdetFileName);
FileSystem::moveFile("out.idf", outputEpmidfFileName);
inputFileName = outputEpmidfFileName;
}

if (runExpandObjects) {
std::string expandObjectsPath = exeDirectory + "ExpandObjects" + exeExtension;
if (!fileExists(expandObjectsPath)) {
DisplayString(state, "ERROR: Could not find ExpandObjects executable: " + getAbsolutePath(expandObjectsPath) + ".");
std::string expandObjectsPath = exeDirectory + "ExpandObjects" + FileSystem::exeExtension;
if (!FileSystem::fileExists(expandObjectsPath)) {
DisplayString(state, "ERROR: Could not find ExpandObjects executable: " + FileSystem::getAbsolutePath(expandObjectsPath) + ".");
exit(EXIT_FAILURE);
}
std::string expandObjectsCommand = "\"" + expandObjectsPath + "\"";
bool inputFileNamedIn = (getAbsolutePath(inputFileName) == getAbsolutePath("in.idf"));
bool inputFileNamedIn = (FileSystem::getAbsolutePath(inputFileName) == FileSystem::getAbsolutePath("in.idf"));

// check if IDD actually exists since ExpandObjects still requires it
if (!fileExists(inputIddFileName)) {
DisplayString(state, "ERROR: Could not find input data dictionary: " + getAbsolutePath(inputIddFileName) + ".");
if (!FileSystem::fileExists(inputIddFileName)) {
DisplayString(state, "ERROR: Could not find input data dictionary: " + FileSystem::getAbsolutePath(inputIddFileName) + ".");
DisplayString(state, errorFollowUp);
exit(EXIT_FAILURE);
}

bool iddFileNamedEnergy = (getAbsolutePath(inputIddFileName) == getAbsolutePath("Energy+.idd"));
bool iddFileNamedEnergy = (FileSystem::getAbsolutePath(inputIddFileName) == FileSystem::getAbsolutePath("Energy+.idd"));

if (!inputFileNamedIn) linkFile(inputFileName.c_str(), "in.idf");
if (!iddFileNamedEnergy) linkFile(inputIddFileName, "Energy+.idd");
systemCall(expandObjectsCommand);
if (!inputFileNamedIn) removeFile("in.idf");
if (!iddFileNamedEnergy) removeFile("Energy+.idd");
moveFile("expandedidf.err", outputExperrFileName);
if (fileExists("expanded.idf")) {
moveFile("expanded.idf", outputExpidfFileName);
if (!inputFileNamedIn) FileSystem::linkFile(inputFileName.c_str(), "in.idf");
if (!iddFileNamedEnergy) FileSystem::linkFile(inputIddFileName, "Energy+.idd");
FileSystem::systemCall(expandObjectsCommand);
if (!inputFileNamedIn) FileSystem::removeFile("in.idf");
if (!iddFileNamedEnergy) FileSystem::removeFile("Energy+.idd");
FileSystem::moveFile("expandedidf.err", outputExperrFileName);
if (FileSystem::fileExists("expanded.idf")) {
FileSystem::moveFile("expanded.idf", outputExpidfFileName);
inputFileName = outputExpidfFileName;
}
}
Expand Down Expand Up @@ -730,20 +729,20 @@ namespace CommandLineInterface {

int runReadVarsESO(EnergyPlusData &state)
{
std::string readVarsPath = exeDirectory + "ReadVarsESO" + exeExtension;
std::string readVarsPath = exeDirectory + "ReadVarsESO" + FileSystem::exeExtension;

if (!fileExists(readVarsPath)) {
readVarsPath = exeDirectory + "PostProcess" + pathChar + "ReadVarsESO" + exeExtension;
if (!fileExists(readVarsPath)) {
DisplayString(state, "ERROR: Could not find ReadVarsESO executable: " + getAbsolutePath(readVarsPath) + ".");
if (!FileSystem::fileExists(readVarsPath)) {
readVarsPath = exeDirectory + "PostProcess" + pathChar + "ReadVarsESO" + FileSystem::exeExtension;
if (!FileSystem::fileExists(readVarsPath)) {
DisplayString(state, "ERROR: Could not find ReadVarsESO executable: " + FileSystem::getAbsolutePath(readVarsPath) + ".");
return EXIT_FAILURE;
}
}

std::string const RVIfile = inputDirPathName + inputFileNameOnly + ".rvi";
std::string const MVIfile = inputDirPathName + inputFileNameOnly + ".mvi";

const auto rviFileExists = fileExists(RVIfile);
const auto rviFileExists = FileSystem::fileExists(RVIfile);
if (!rviFileExists) {
std::ofstream ofs{RVIfile};
if (!ofs.good()) {
Expand All @@ -754,7 +753,7 @@ namespace CommandLineInterface {
}
}

const auto mviFileExists = fileExists(MVIfile);
const auto mviFileExists = FileSystem::fileExists(MVIfile);
if (!mviFileExists) {
std::ofstream ofs{MVIfile};
if (!ofs.good()) {
Expand All @@ -771,14 +770,14 @@ namespace CommandLineInterface {
std::string const readVarsMviCommand = "\"" + readVarsPath + "\" \"" + MVIfile + "\" unlimited";

// systemCall will be responsible to handle to above command on Windows versus Unix
systemCall(readVarsRviCommand);
systemCall(readVarsMviCommand);
FileSystem::systemCall(readVarsRviCommand);
FileSystem::systemCall(readVarsMviCommand);

if (!rviFileExists) removeFile(RVIfile.c_str());
if (!rviFileExists) FileSystem::removeFile(RVIfile.c_str());

if (!mviFileExists) removeFile(MVIfile.c_str());
if (!mviFileExists) FileSystem::removeFile(MVIfile.c_str());

moveFile("readvars.audit", outputRvauditFileName);
FileSystem::moveFile("readvars.audit", outputRvauditFileName);
return EXIT_SUCCESS;
}

Expand Down
12 changes: 7 additions & 5 deletions src/EnergyPlus/DataSystemVariables.cc
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ namespace DataSystemVariables {
using DataStringGlobals::CurrentWorkingFolder;
using DataStringGlobals::pathChar;
using DataStringGlobals::ProgramPath;
using namespace FileSystem;

// Data
// -only module should be available to other modules and routines.
Expand Down Expand Up @@ -242,7 +241,7 @@ namespace DataSystemVariables {
FileFound = false;
CheckedFileName.clear();
InputFileName = originalInputFileName;
makeNativePath(InputFileName);
FileSystem::makeNativePath(InputFileName);

std::vector<std::pair<std::string, std::string>> pathsChecked;

Expand All @@ -262,10 +261,12 @@ namespace DataSystemVariables {
if (FileSystem::fileExists(pathsToCheck[i].first)) {
FileFound = true;
CheckedFileName = pathsToCheck[i].first;
print(state.files.audit, "{}={}\n", "found (" + pathsToCheck[i].second +")", getAbsolutePath(CheckedFileName));
print(state.files.audit, "{}={}\n", "found (" + pathsToCheck[i].second +")", FileSystem::getAbsolutePath(CheckedFileName));
return;
} else {
std::pair <std::string,std::string> currentPath(getParentDirectoryPath(getAbsolutePath(pathsToCheck[i].first)), pathsToCheck[i].second);
std::pair <std::string,std::string> currentPath(
FileSystem::getParentDirectoryPath(FileSystem::getAbsolutePath(pathsToCheck[i].first)),
pathsToCheck[i].second);
bool found = false;
for(auto path: pathsChecked){
if (path.first == currentPath.first){
Expand All @@ -275,7 +276,8 @@ namespace DataSystemVariables {
if (!found){
pathsChecked.push_back(currentPath);
}
print(state.files.audit, "{}={}\n", "not found (" + pathsToCheck[i].second +")\"", getAbsolutePath(pathsToCheck[i].first));
print(state.files.audit, "{}={}\n", "not found (" + pathsToCheck[i].second +")\"",
FileSystem::getAbsolutePath(pathsToCheck[i].first));
}
}
if (!FileFound) {
Expand Down
23 changes: 22 additions & 1 deletion src/EnergyPlus/FileSystem.cc
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
// Standard C++ library
#include <errno.h>
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Expand Down Expand Up @@ -257,11 +258,31 @@ namespace FileSystem {

void moveFile(std::string const &filePath, std::string const &destination)
{
if (!fileExists(filePath)) {
return;
}
#ifdef _WIN32
//Note: on Windows, rename function doesn't always replace the existing file so MoveFileExA is used
MoveFileExA(filePath.c_str(), destination.c_str(), MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING);
#else
rename(filePath.c_str(), destination.c_str());
// Start by removing the destination file. rename fails silently, so you don't want to silently use a potentially outdated file...
removeFile(destination);
int result = rename(filePath.c_str(), destination.c_str());
if ((result != 0) || !fileExists(destination)) {
// rename won't work for cross-device (eg: copying from one disk to another)

// Do a copy of the content
{
std::ifstream src(filePath, std::ios::binary);
std::ofstream dst(destination, std::ios::binary);
dst << src.rdbuf();
}

// Then remove original
if (fileExists(destination)) {
removeFile(filePath);
}
}
#endif
}

Expand Down
2 changes: 2 additions & 0 deletions src/EnergyPlus/FileSystem.hh
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,10 @@ namespace FileSystem {

std::string getProgramPath();

// For `a/b/c.txt.idf` it returns `idf` (anything after last dot, not including the dot)
std::string getFileExtension(std::string const &fileName);

// Turns a/b/c.txt.idf into a/b/c.txt
std::string removeFileExtension(std::string const &fileName);

void makeDirectory(std::string const &directoryPath);
Expand Down
Loading