diff --git a/CMakeLists.txt b/CMakeLists.txt index f3e438dde755d32838527340444cc7ea8950bbe6..70cd1703807158f5af893bd044864b256fea61a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,7 @@ set(SRC_FILES strops.cpp translators.cpp randomgen.cpp + compile.cpp ) set(API_HEADERS_CPP_DIR eisgenerator/) diff --git a/cap.cpp b/cap.cpp index 191fad6a02b0996f1af909d0ba86925ebe2c939d..eb8078185e6a4054bee66742cacf111cf7bfa055 100644 --- a/cap.cpp +++ b/cap.cpp @@ -45,3 +45,13 @@ size_t Cap::paramCount() { return 1; } + +std::string Cap::getCode(std::vector<std::string>& parameters) +{ + std::string firstParameter = getUniqueName() + "_0"; + parameters.push_back(firstParameter); + std::string real = "0"; + std::string imag = "0.0-(1.0/(" + firstParameter + "*omega))"; + std::string out = "std::complex<fvalue>(" + real + ", " + imag + ")"; + return out; +} diff --git a/compile.cpp b/compile.cpp new file mode 100644 index 0000000000000000000000000000000000000000..00b86298c610a1bfce02b22effc2b9950834eb11 --- /dev/null +++ b/compile.cpp @@ -0,0 +1,149 @@ +#include "compile.h" + +#include <filesystem> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <stdexcept> +#include <sys/wait.h> +#include <dlfcn.h> + +#include "log.h" + +using namespace eis; + +static constexpr int PIPE_READ = 0; +static constexpr int PIPE_WRITE = 1; + +int eis::compile_code(const std::string& code, const std::string& outputName) +{ + int childStdinPipe[2]; + int childStdoutPipe[2]; + + int ret = pipe(childStdinPipe); + if(ret < 0) + throw std::runtime_error("Not enough pipe to create child"); + ret = pipe(childStdoutPipe); + if(ret < 0) + throw std::runtime_error("Not enough pipe to create child"); + + int childPid = fork(); + + if(childPid < 0) + throw std::runtime_error("Unable to create child"); + + if(childPid == 0) + { + eis::Log(eis::Log::DEBUG)<<"Compile starting"; + + if (dup2(childStdinPipe[PIPE_READ], STDIN_FILENO) == -1) + exit(errno); + if (dup2(childStdoutPipe[PIPE_WRITE], STDOUT_FILENO) == -1) + exit(errno); + if (dup2(childStdoutPipe[PIPE_WRITE], STDERR_FILENO) == -1) + exit(errno); + + close(childStdinPipe[PIPE_WRITE]); + close(childStdinPipe[PIPE_READ]); + close(childStdoutPipe[PIPE_WRITE]); + close(childStdoutPipe[PIPE_READ]); + + ret = execlp("g++", "gcc", "--shared", "-O2", "-ffast-math", "-ftree-vectorize", "-mavx", "-x", "c++", "-o", outputName.c_str(), "-", NULL); + + exit(ret); + } + else + { + eis::Log(eis::Log::DEBUG)<<"Sending code to child"; + + close(childStdinPipe[PIPE_READ]); + close(childStdoutPipe[PIPE_WRITE]); + + ret = write(childStdinPipe[PIPE_WRITE], code.c_str(), code.size()); + if(ret < 0) + throw std::runtime_error("Could not pass code to compiler"); + close(childStdinPipe[PIPE_WRITE]); + + char ch; + while (read(childStdoutPipe[PIPE_READ], &ch, 1) == 1) + eis::Log(eis::Log::DEBUG, false)<<ch; + + close(childStdoutPipe[PIPE_READ]); + + eis::Log(eis::Log::DEBUG)<<"Wating for child to exit"; + + int exitCode; + waitpid(childPid, &exitCode, 0); + if(exitCode != 0) + eis::Log(eis::Log::ERROR)<<"Failed to compile "<<exitCode; + eis::Log(eis::Log::DEBUG)<<"Chiled exited"; + return exitCode; + } + return -1; +} + +std::string eis::getTempdir() +{ + char* tmpEnv = getenv("TMP"); + char* tempEnv = getenv("TEMP"); + char* tempDirEnv = getenv("TEMPDIR"); + + std::filesystem::path path; + if(tmpEnv && std::string(tmpEnv).length() > 1) + path = tmpEnv; + else if(tempEnv && std::string(tempEnv).length() > 1) + path = tempEnv; + else if(tempDirEnv && std::string(tempDirEnv).length() > 1) + path = tempDirEnv; + else + path = "/tmp"; + path = path/"eis_models"; + + if(!std::filesystem::is_directory(path)) + { + if(!std::filesystem::create_directory(path)) + throw std::runtime_error(path.string() + + "is not a directory and a directory can not be created at this locaion"); + } + + return path; +} + + +CompCache* CompCache::getInstance() +{ + if(!instance) + instance = new CompCache(); + return instance; +} + +bool CompCache::addObject(size_t uuid, const CompiledObject& object) +{ + CompiledObject* foundobject = getObject(uuid); + if(foundobject) + return false; + + objects.insert({uuid, new CompiledObject(object)}); + return true; +} + +CompiledObject* CompCache::getObject(size_t uuid) +{ + auto search = objects.find(uuid); + if(search == objects.end()) + return nullptr; + else + return search->second; +} + +void CompCache::dropAllObjects() +{ + for(std::pair<size_t, CompiledObject*> object : objects) + { + dlclose(object.second->objectCode); + delete object.second; + } + + objects.clear(); +} diff --git a/compile.h b/compile.h new file mode 100644 index 0000000000000000000000000000000000000000..ce0ababf8d84d189613ae5021faa17b6c0c08682 --- /dev/null +++ b/compile.h @@ -0,0 +1,41 @@ +#include <string> +#include <vector> +#include <map> +#include <complex> + +#include "eistype.h" + +namespace eis +{ + +int compile_code(const std::string& code, const std::string& outputName); + +std::string getTempdir(); + +struct CompiledObject +{ + void* objectCode; + std::vector<std::complex<fvalue>>(*symbol)(const std::vector<fvalue>&, const std::vector<fvalue>&); +}; + +class CompCache +{ +public: + +private: + + inline static CompCache* instance = nullptr; + std::map<size_t, CompiledObject*> objects; + CompCache() {}; + +public: + + static CompCache* getInstance(); + CompCache(const CompCache&) = delete; + CompCache& operator=(const CompCache&) = delete; + bool addObject(size_t uuid, const CompiledObject& object); + CompiledObject* getObject(size_t uuid); + void dropAllObjects(); +}; + +} diff --git a/componant.cpp b/componant.cpp index 36bf5c810e79650e476f7b7b42ba83af46dd1e73..d016bbd61143749eeb4b749fa1b1409693456299 100644 --- a/componant.cpp +++ b/componant.cpp @@ -56,13 +56,13 @@ std::string Componant::getUniqueName() { if(uniqueName.empty()) { - uniqueName.assign(getComponantChar(), 5); - for(size_t i = 1; i < uniqueName.size(); ++i) + uniqueName.push_back(getComponantChar()); + for(size_t i = 0; i < 3; ++i) { char ch = static_cast<char>(rd::rand(122-65)+65); if(ch > 90 && ch < 97) ch = ch + 6; - uniqueName[i] = ch; + uniqueName.push_back(ch); } } return uniqueName; @@ -95,3 +95,14 @@ Componant* Componant::copy(Componant* componant) } return nullptr; } + +bool Componant::compileable() +{ + std::vector<std::string> parameters; + return !getCode(parameters).empty(); +} + +std::string Componant::getCode(std::vector<std::string>& parameters) +{ + return std::string(); +} diff --git a/constantphase.cpp b/constantphase.cpp index 12aba56b1f5d4a1ebb21c9d94420f11dc4f09ddc..4a9f6eca12b6412262f60e23c5dfc192e9a5c3a9 100644 --- a/constantphase.cpp +++ b/constantphase.cpp @@ -56,8 +56,9 @@ void Cpe::setDefaultParam(size_t count, bool defaultToRange) std::complex<fvalue> Cpe::execute(fvalue omega) { assert(ranges.size() == paramCount()); - return std::complex<fvalue>((1.0/(ranges[0][ranges[0].step]*pow(omega, ranges[1][ranges[1].step])))*cos((M_PI/2)*ranges[1][ranges[1].step]), - 0-(1.0/(ranges[0][ranges[0].step]*pow(omega, ranges[1][ranges[1].step])))*sin((M_PI/2)*ranges[1][ranges[1].step])); + fvalue real = (1.0/(ranges[0][ranges[0].step]*std::pow(omega, ranges[1][ranges[1].step])))*std::cos((M_PI/2)*ranges[1][ranges[1].step]); + fvalue imag = 0-(1.0/(ranges[0][ranges[0].step]*std::pow(omega, ranges[1][ranges[1].step])))*std::sin((M_PI/2)*ranges[1][ranges[1].step]); + return std::complex<fvalue>(real, imag); } size_t Cpe::paramCount() @@ -69,3 +70,15 @@ char Cpe::getComponantChar() const { return Cpe::staticGetComponantChar(); } + +std::string Cpe::getCode(std::vector<std::string>& parameters) +{ + std::string firstParameter = getUniqueName() + "_0"; + std::string secondParameter = getUniqueName() + "_1"; + parameters.push_back(firstParameter); + parameters.push_back(secondParameter); + std::string real = "(1.0/(" + firstParameter + "*std::pow(omega," + secondParameter + ")))*std::cos((M_PI/2)*" + secondParameter + ")"; + std::string imag = "0-(1.0/(" + firstParameter + "*std::pow(omega," + secondParameter + ")))*std::sin((M_PI/2)*" + secondParameter + ")"; + std::string out = "std::complex<fvalue>(" + real +", " + imag + ")"; + return out; +} diff --git a/eisgenerator/cap.h b/eisgenerator/cap.h index 54ef8a473751e610aaacf3f9d8094288e4f0207c..40a1080ae687cd8e05c2de7662b244eb52390115 100644 --- a/eisgenerator/cap.h +++ b/eisgenerator/cap.h @@ -17,6 +17,7 @@ public: virtual char getComponantChar() const override; static constexpr char staticGetComponantChar(){return 'c';} virtual std::string componantName() const override {return "Capacitor";} + virtual std::string getCode(std::vector<std::string>& parameters) override; virtual ~Cap() = default; }; diff --git a/eisgenerator/componant.h b/eisgenerator/componant.h index a4c101cb8395b459a2f26b5f88d059147caa139e..6bc1b1a94ce498004435f1f23f70b743c745e332 100644 --- a/eisgenerator/componant.h +++ b/eisgenerator/componant.h @@ -31,6 +31,8 @@ class Componant virtual char getComponantChar() const = 0; virtual std::string getComponantString(bool currentValue = true) const; virtual std::string componantName() const = 0; + virtual std::string getCode(std::vector<std::string>& parameters); + virtual bool compileable(); std::string getUniqueName(); diff --git a/eisgenerator/constantphase.h b/eisgenerator/constantphase.h index 7a2fb27872c82500db0e18014edd631de369e7ad..8bb0c58d0dae330285acd52aa7858a3362283dab 100644 --- a/eisgenerator/constantphase.h +++ b/eisgenerator/constantphase.h @@ -21,7 +21,7 @@ public: static constexpr char staticGetComponantChar(){return 'p';} virtual std::string componantName() const override {return "ConstantPhase";} virtual ~Cpe() = default; - + virtual std::string getCode(std::vector<std::string>& parameters) override; }; } diff --git a/eisgenerator/inductor.h b/eisgenerator/inductor.h index 61a5ab24b6baf549086cc7c8491a739c69c5d30b..a410eccb6c25687d6f926b62002fd3499c3d8eac 100644 --- a/eisgenerator/inductor.h +++ b/eisgenerator/inductor.h @@ -17,6 +17,7 @@ public: virtual char getComponantChar() const override; static constexpr char staticGetComponantChar(){return 'l';} virtual std::string componantName() const override {return "Inductor";} + virtual std::string getCode(std::vector<std::string>& parameters) override; virtual ~Inductor() = default; }; diff --git a/eisgenerator/model.h b/eisgenerator/model.h index 8db355a641c935455c0ba6c10730c2a346628d9a..1dbac364a6d692d8c27754fb87b4d76cb65dafc6 100644 --- a/eisgenerator/model.h +++ b/eisgenerator/model.h @@ -5,12 +5,15 @@ #include <string> #include <vector> #include <functional> + #include "eistype.h" #include "componant.h" namespace eis { +struct CompiledObject; + class Model { private: @@ -19,6 +22,7 @@ private: std::string getParamStr(const std::string& str, size_t index); static size_t paramSkipIndex(const std::string& str, size_t index); static void addComponantToFlat(Componant* componant, std::vector<Componant*>* flatComponants); + std::vector<fvalue> getFlatParameters(); static void sweepThreadFn(std::vector<std::vector<DataPoint>>* data, Model* model, size_t start, size_t stop, const Range& omega); @@ -29,6 +33,8 @@ private: std::vector<Componant*> _bracketComponants; std::string _modelStr; std::vector<Componant*> _flatComponants; + std::string _modelUuid; + CompiledObject* _compiledModel = nullptr; public: Model(const std::string& str, size_t paramSweepCount = 100, bool defaultToRange = true); @@ -42,12 +48,15 @@ public: std::string getModelStr() const; std::string getModelStrWithParam(size_t index); std::string getModelStrWithParam() const; + size_t getUuid(); std::vector<Componant*> getFlatComponants(Componant *model = nullptr); size_t getParameterCount(); + bool compile(); bool isReady(); void resolveSteps(int64_t index); size_t getRequiredStepsForSweeps(); bool isParamSweep(); + std::string getCode(); std::vector<size_t> getRecommendedParamIndices(eis::Range omegaRange, double distance, bool threaded = false); }; diff --git a/eisgenerator/paralellseriel.h b/eisgenerator/paralellseriel.h index cd77b3e6b20eae17bf0c38c21be1b312b51119a2..902bbe4874a214e7467271b4a5760c816242232a 100644 --- a/eisgenerator/paralellseriel.h +++ b/eisgenerator/paralellseriel.h @@ -20,6 +20,8 @@ public: virtual std::string getComponantString(bool currentValue = true) const override; static constexpr char staticGetComponantChar(){return 'd';} virtual std::string componantName() const override {return "Parallel";} + virtual bool compileable() override; + virtual std::string getCode(std::vector<std::string>& parameters) override; }; class Serial: public Componant @@ -36,6 +38,8 @@ public: virtual std::string getComponantString(bool currentValue = true) const override; static constexpr char staticGetComponantChar(){return 's';} virtual std::string componantName() const override {return "Serial";} + virtual bool compileable() override; + virtual std::string getCode(std::vector<std::string>& parameters) override; }; } diff --git a/eisgenerator/resistor.h b/eisgenerator/resistor.h index 6822313535aa38ad1f402675ca440e94f27ba31f..53501b1c2c451b76d41d0f7894525c596481b218 100644 --- a/eisgenerator/resistor.h +++ b/eisgenerator/resistor.h @@ -15,6 +15,7 @@ public: virtual char getComponantChar() const override; static constexpr char staticGetComponantChar(){return 'r';} virtual std::string componantName() const override {return "Resistor";} + virtual std::string getCode(std::vector<std::string>& parameters) override; virtual ~Resistor() = default; }; diff --git a/eisgenerator/warburg.h b/eisgenerator/warburg.h index 706d9afcb3bd526fe2f034dbdf295eea12b953c5..4ace89f365abae96a59b3e796b59d82c311d6c24 100644 --- a/eisgenerator/warburg.h +++ b/eisgenerator/warburg.h @@ -17,6 +17,7 @@ public: virtual char getComponantChar() const override; static constexpr char staticGetComponantChar(){return 'w';} virtual std::string componantName() const override {return "Warburg";} + virtual std::string getCode(std::vector<std::string>& parameters) override; virtual ~Warburg() = default; }; diff --git a/inductor.cpp b/inductor.cpp index 77c9714a4edde369b717a2ba67b121064e937ed4..32428a342e73de317e5a162191ae085bce0eeaec 100644 --- a/inductor.cpp +++ b/inductor.cpp @@ -45,3 +45,11 @@ char Inductor::getComponantChar() const { return staticGetComponantChar(); } + +std::string Inductor::getCode(std::vector<std::string>& parameters) +{ + parameters.push_back(getUniqueName() + "_0"); + std::string N = parameters.back() + "*omega"; + std::string out = "std::complex<fvalue>(0, " + N + ")"; + return out; +} diff --git a/main.cpp b/main.cpp index aa7a90e5e483debbd6cd5a89a67cfd0005d6537e..12e1387f1d255ea39ca23302be5e75d4f352e6d5 100644 --- a/main.cpp +++ b/main.cpp @@ -85,11 +85,18 @@ static void runParamSweep(const Config& config, eis::Model& model) size_t count = model.getRequiredStepsForSweeps(); eis::Log(eis::Log::INFO)<<"Executeing "<<count<<" steps"; + if(!config.noCompile) + model.compile(); + auto start = std::chrono::high_resolution_clock::now(); std::vector<std::vector<eis::DataPoint>> allSweeps; if(config.threaded) + { + eis::Log(eis::Log::INFO)<<"Calculateing sweeps in threads"; allSweeps = model.executeAllSweeps(config.omegaRange); + eis::Log(eis::Log::INFO)<<"Done"; + } for(size_t i = 0; i < count; ++i) { @@ -98,33 +105,37 @@ static void runParamSweep(const Config& config, eis::Model& model) data = allSweeps[i]; else data = model.executeSweep(config.omegaRange, i); - if(config.normalize) - eis::normalize(data); - if(config.reduce) + + if(!config.noSave) { - size_t initalDataSize = data.size(); - data = eis::reduceRegion(data); - if(data.size() < initalDataSize/8) + if(config.normalize) + eis::normalize(data); + if(config.reduce) { - eis::Log(eis::Log::INFO)<<"\nskipping output for step "<<i - <<" as data has no interesting region"; - continue; + size_t initalDataSize = data.size(); + data = eis::reduceRegion(data); + if(data.size() < initalDataSize/8) + { + eis::Log(eis::Log::INFO)<<"\nskipping output for step "<<i + <<" as data has no interesting region"; + continue; + } + //data = eis::rescale(data, initalDataSize); } - //data = eis::rescale(data, initalDataSize); - } - if(config.skipLinear && i > 0) - { - fvalue correlation = std::abs(pearsonCorrelation(data)); - if(correlation > 0.5) + if(config.skipLinear && i > 0) { - eis::Log(eis::Log::INFO)<<"skipping output for step "<<i - <<" as data is too linear: "<<correlation; - continue; + fvalue correlation = std::abs(pearsonCorrelation(data)); + if(correlation > 0.5) + { + eis::Log(eis::Log::INFO)<<"skipping output for step "<<i + <<" as data is too linear: "<<correlation; + continue; + } } - } - eis::saveToDisk(eis::EisSpectra(data, model.getModelStrWithParam(i), ""), std::string(PARA_SWEEP_OUTPUT_DIR)+std::string("/")+std::to_string(i)+".csv"); + eis::saveToDisk(eis::EisSpectra(data, model.getModelStrWithParam(i), ""), std::string(PARA_SWEEP_OUTPUT_DIR)+std::string("/")+std::to_string(i)+".csv"); + } eis::Log(eis::Log::INFO, false)<<'.'; } auto end = std::chrono::high_resolution_clock::now(); @@ -352,6 +363,10 @@ int main(int argc, char** argv) { outputRanges(config, model); } + else if(config.mode == MODE_CODE) + { + std::cout<<model.getCode(); + } else { if(model.isParamSweep()) diff --git a/model.cpp b/model.cpp index 5a8f420a71a862ad2d3d5f93d98bdb8a1957ddcc..fd9d1ccfd7471e2de3f0da53cc3b752956cf36d6 100644 --- a/model.cpp +++ b/model.cpp @@ -2,13 +2,18 @@ #include <model.h> #include <iostream> #include <assert.h> +#include <string> #include <vector> #include <array> #include <thread> #include <fstream> #include <algorithm> #include <execution> +#include <dlfcn.h> +#include <functional> +#include "componant.h" +#include "eistype.h" #include "strops.h" #include "cap.h" #include "resistor.h" @@ -20,6 +25,8 @@ #include "log.h" #include "normalize.h" #include "basicmath.h" +#include "randomgen.h" +#include "compile.h" using namespace eis; @@ -196,6 +203,7 @@ Model& Model::operator=(const Model& in) _bracketComponants.clear(); _flatComponants.clear(); _model = Componant::copy(in._model); + _compiledModel = in._compiledModel; return *this; } @@ -204,6 +212,21 @@ Model::~Model() delete _model; } +std::vector<fvalue> Model::getFlatParameters() +{ + std::vector<Componant*> flatComponants = getFlatComponants(); + + std::vector<fvalue> out; + out.reserve(getParameterCount()); + for(Componant* componant : flatComponants) + { + const std::vector<Range> ranges = componant->getParamRanges(); + for(const Range& range : ranges) + out.push_back(range.stepValue()); + } + return out; +} + DataPoint Model::execute(fvalue omega, size_t index) { if(_model) @@ -307,12 +330,29 @@ std::vector<DataPoint> Model::executeSweep(const Range& omega, size_t index) { std::vector<DataPoint> results; results.reserve(omega.count); - for(size_t i = 0; i < omega.count; ++i) + + if(_compiledModel) + { + resolveSteps(index); + std::vector<fvalue> parameters = getFlatParameters(); + const std::vector<fvalue> omegas = omega.getRangeVector(); + std::vector<std::complex<fvalue>> values = _compiledModel->symbol(parameters, omegas); + for(size_t i = 0; i < omegas.size(); ++i) + { + DataPoint dataPoint; + dataPoint.omega = omegas[i]; + dataPoint.im = values[i]; + results.push_back(dataPoint); + } + } + else { - fvalue omegaStep = omega[i]; - results.push_back(execute(omegaStep, index)); + for(size_t i = 0; i < omega.count; ++i) + { + fvalue omegaStep = omega[i]; + results.push_back(execute(omegaStep, index)); + } } - return results; } @@ -373,22 +413,22 @@ void Model::resolveSteps(int64_t index) std::vector<size_t> placeMagnitude; placeMagnitude.reserve(flatRanges.size()); - Log(Log::DEBUG)<<"Magnitudes:"; + //Log(Log::DEBUG)<<"Magnitudes:"; for(size_t i = 0; i < flatRanges.size(); ++i) { size_t magnitude = 1; for(int64_t j = static_cast<int64_t>(i)-1; j >= 0; --j) magnitude = magnitude*flatRanges[j]->count; placeMagnitude.push_back(magnitude); - Log(Log::DEBUG)<<placeMagnitude.back(); + //Log(Log::DEBUG)<<placeMagnitude.back(); } - Log(Log::DEBUG)<<"Steps for index "<<index<<" ranges "<<flatRanges.size()<<" Ranges:"; + //Log(Log::DEBUG)<<"Steps for index "<<index<<" ranges "<<flatRanges.size()<<" Ranges:"; for(int64_t i = flatRanges.size()-1; i >= 0; --i) { flatRanges[i]->step = index/placeMagnitude[i]; index = index % placeMagnitude[i]; - Log(Log::DEBUG)<<placeMagnitude[i]<<'('<<flatRanges[i]->step<<')'<<(i == 0 ? "" : " + "); + //Log(Log::DEBUG)<<placeMagnitude[i]<<'('<<flatRanges[i]->step<<')'<<(i == 0 ? "" : " + "); } } @@ -519,3 +559,85 @@ std::vector<size_t> Model::getRecommendedParamIndices(eis::Range omegaRange, dou eis::Log(eis::Log::INFO, false)<<'\n'; return indices; } + +size_t Model::getUuid() +{ + return std::hash<std::string>{}(getModelStr()); +} + +bool Model::compile() +{ + if(!_model->compileable()) + { + Log(Log::WARN)<<"This model could not be compiled, expect performance degredation"; + return false; + } + + CompCache* cache = CompCache::getInstance(); + + _compiledModel = cache->getObject(getUuid()); + if(!_compiledModel) + { + std::filesystem::path tmp = getTempdir(); + size_t uuid = getUuid(); + + std::filesystem::path path = tmp/(std::to_string(getUuid())+".so"); + int ret = compile_code(getCode(), path); + if(ret != 0) + { + Log(Log::WARN)<<"Unable to compile model!! expect performance degredation"; + return false; + } + + CompiledObject object; + object.objectCode = dlopen(path.c_str(), RTLD_NOW); + if(!object.objectCode) + throw std::runtime_error("Unable to dlopen compiled model " + std::string(dlerror())); + + std::string symbolName = "model_" + std::to_string(getUuid()); + object.symbol = + reinterpret_cast<std::vector<std::complex<fvalue>>(*)(const std::vector<fvalue>&, const std::vector<fvalue>&)> + (dlsym(object.objectCode, symbolName.c_str())); + + if(!object.symbol) + throw std::runtime_error(path.string() + " dosent have a symbol " + symbolName); + + cache->addObject(uuid, object); + _compiledModel = cache->getObject(uuid); + } + + return true; +} + +std::string Model::getCode() +{ + if(!_model || !_model->compileable()) + return ""; + + std::vector<std::string> parameters; + std::string formular = _model->getCode(parameters); + + std::string out = + "#include <cmath>\n" + "#include <cassert>\n" + "#include <vector>\n" + "#include <complex>\n\n" + "typedef float fvalue;\n\n" + "extern \"C\"\n{\n\n" + "std::vector<std::complex<fvalue>> model_"; + out.append(std::to_string(getUuid())); + out.append("(const std::vector<fvalue>& parameters, const std::vector<fvalue> omegas)\n{\n\tassert(parameters.size() == "); + out.append(std::to_string(parameters.size())); + out.append(");\n\n"); + out.append("\tstd::vector<std::complex<fvalue>> out(omegas.size());\n"); + + for(size_t i = 0; i < parameters.size(); ++i) + out.append("\tfvalue " + parameters[i] + " = parameters[" + std::to_string(i) + "];\n"); + + out.append("\tfor(size_t i = 0; i < omegas.size(); ++i)\n\t{\n"); + out.append("\t\tconst fvalue& omega = omegas[i];\n"); + out.append("\t\tout[i] = "); + out.append(formular); + out.append(";\n\t}\n\treturn out;\n}\n\n}\n"); + return out; +} diff --git a/options.h b/options.h index 9624fa7fecc34b96aff1ea22aa64c63ca2038c99..9689d7f341783bbc5139144fe70620e9216bbc07 100644 --- a/options.h +++ b/options.h @@ -26,11 +26,13 @@ static struct argp_option options[] = {"invert", 'i', 0, 0, "inverts the imaginary axis"}, {"noise", 'x', "[AMPLITUDE]", 0, "add noise to output"}, {"input-type", 't', "[STRING]", 0, "set input string type, possible values: eis, boukamp, relaxis, madap"}, - {"find-range", 'f', "[STRING]", 0, "mode, possible values: export, find-range, export-ranges"}, + {"mode", 'f', "[STRING]", 0, "mode, possible values: export, code, find-range, export-ranges"}, {"range-distance", 'd', "[DISTANCE]", 0, "distance from a previous point where a range is considered \"new\""}, {"parallel", 'p', 0, 0, "run on multiple threads"}, {"skip-linear", 'e', 0, 0, "dont output param sweeps that create linear nyquist plots"}, {"default-to-range", 'b', 0, 0, "if a element has no paramters, default to assigning it a range instead of a single value"}, + {"no-compile", 'z', 0, 0, "dont compile the model into a shared object"}, + {"no-save", 'y', 0, 0, "dont save sweeps"}, { 0 } }; @@ -49,6 +51,7 @@ enum MODE_FIND_RANGE, MODE_OUTPUT_RANGE_DATAPOINTS, MODE_INVALID, + MODE_CODE }; struct Config @@ -65,6 +68,8 @@ struct Config bool threaded = false; bool skipLinear = false; bool defaultToRange = false; + bool noCompile = false; + bool noSave = false; double noise = 0; double rangeDistance = 0.35; @@ -93,6 +98,8 @@ static int parseMode(const std::string& str) return MODE_FIND_RANGE; else if(str == "export-ranges") return MODE_OUTPUT_RANGE_DATAPOINTS; + else if(str == "code") + return MODE_CODE; return MODE_INVALID; } @@ -190,6 +197,12 @@ parse_opt (int key, char *arg, struct argp_state *state) case 'b': config->defaultToRange = true; break; + case 'y': + config->noSave = true; + break; + case 'z': + config->noCompile = true; + break; default: return ARGP_ERR_UNKNOWN; } diff --git a/paralellseriel.cpp b/paralellseriel.cpp index c36893912ef211826496417da6ecb5b21b3031a8..e661372f14a30abb42337e6bcaeb747e1cd1c48d 100644 --- a/paralellseriel.cpp +++ b/paralellseriel.cpp @@ -1,4 +1,5 @@ #include "paralellseriel.h" +#include "componant.h" using namespace eis; @@ -49,6 +50,30 @@ std::string Parallel::getComponantString(bool currentValue) const return out; } +bool Parallel::compileable() +{ + for(Componant* componant : componants) + { + if(!componant->compileable()) + return false; + } + return true; +} + +std::string Parallel::getCode(std::vector<std::string>& parameters) +{ + std::string out = "std::complex<fvalue>(1,0)/("; + for(Componant* componant : componants) + { + out += "std::complex<fvalue>(1,0)/(" + componant->getCode(parameters) + ") + "; + } + out.pop_back(); + out.pop_back(); + out.pop_back(); + out.push_back(')'); + return out; +} + Serial::Serial(std::vector<Componant*> componantsIn): componants(componantsIn) { } @@ -98,3 +123,27 @@ std::string Serial::getComponantString(bool currentValue) const out.back() = ')'; return out; } + +bool Serial::compileable() +{ + for(Componant* componant : componants) + { + if(!componant->compileable()) + return false; + } + return true; +} + +std::string Serial::getCode(std::vector<std::string>& parameters) +{ + std::string out = "("; + for(Componant* componant : componants) + { + out += "(" + componant->getCode(parameters) + ") + "; + } + out.pop_back(); + out.pop_back(); + out.pop_back(); + out.push_back(')'); + return out; +} diff --git a/resistor.cpp b/resistor.cpp index 074eeb6a5ea61122bb9512895ef26e991f6b5dd1..406702b1f7b37fc2929a2ffcc564626dc088785f 100644 --- a/resistor.cpp +++ b/resistor.cpp @@ -46,3 +46,10 @@ char Resistor::getComponantChar() const { return staticGetComponantChar(); } + +std::string Resistor::getCode(std::vector<std::string>& parameters) +{ + parameters.push_back(getUniqueName() + "_0"); + std::string out = "std::complex<fvalue>(" + parameters.back() + ", 0)"; + return out; +} diff --git a/warburg.cpp b/warburg.cpp index 7155d5885bbe504ff4f11a0c9669a18a40b84229..a6c314d12fd4c6573761eb0962a64d989fdc3663 100644 --- a/warburg.cpp +++ b/warburg.cpp @@ -46,3 +46,11 @@ char Warburg::getComponantChar() const { return staticGetComponantChar(); } + +std::string Warburg::getCode(std::vector<std::string>& parameters) +{ + parameters.push_back(getUniqueName() + "_0"); + std::string N = parameters.back() + "/std::sqrt(omega)"; + std::string out = "std::complex<fvalue>(" + N + ", 0-" + N + ")"; + return out; +}