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

Loaders & CircuitExplorer refactoring #927

Merged
merged 10 commits into from
Nov 2, 2021
Merged

Conversation

NadirRoGue
Copy link
Contributor

  • Refactor of loaders to use compile time parameters
  • Update copyright year on source files
  • Refactor CircuitExplorer
  • Adds support for SONATA format

@NadirRoGue NadirRoGue requested a review from Adrien4193 October 28, 2021 14:40
Loader(Scene& scene)
: _scene(scene)
{
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a personal opinion but for me it is a real pain to have non-default constructors in base classes as you need to rewrite it for each subclasses...
It would be easier to decouple initialization and construction like that:

class Loader
{
public:
    virtual ~Loader() = default;
    virtual void onCreate() {}
    void setScene(Scene &scene) {_scene = &scene;}
    Scene &getScene() const {assert(_scene); return *_scene;}

private:
    Scene *_scene = nullptr;
};
    
// On register:
loader->setScene(scene);
loader->onCreate();

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The point of the design is to comply with RAII so that you cannot use a loader without the scene being set up.
Otherwise someone could instantiate the loader without know he must call the setScene method.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes but if they are meant to be registered as a list of abstract objects that will be used in an agnostic fashion using the extension of the files to load, it is not really a problem.

But if you prefer like that it's fine also.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They can always be used manually in an entry point, for instance, when you want to load an specific type of model and do something with it. And then again, doing it with the setScene method breask RAII.

I believe this way is more correct, whereas setting it afterwards may be dangerous.

* @brief The EmptyLoaderParameters struct is a convenience type for loaders
* that do not have any input parameter
*/
struct EmptyLoaderParameters
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is an EmptyMessage already existing in MessageFactory.h, I don't know if you could have used it...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MessageFactory is part of the network library, which does not make sense to link against braynsCommon.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could extract it to brayns/json as it is just an empty struct (don't even need to be a message I realize) with an adapter.

But it can be done in a later pass.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will see. We have to refactor braynsJson, since it does not make sense its called MESSAGE_... (thats semantically correct for network though). I believe we should call the macros something like SERIALIZABLE_.... We can introduce the empty serializable struct on braynsJson in that refactor and remove this struct here.

const JsonValue& params) const override
{
T inputParams;
if (!Json::deserialize<T>(params, inputParams))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use JsonValidator::validate if you want to check all constraints in the JSON schema and have a more detailed error and throw the list of errors in the JSON-RPC error.data field using EntrypointException.

But depending on how you use it, it might already be done in the entrypoint so in this case you don't even need to check the return value.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The entry point just copy the json object that contains the parameter, so Ill add the validation. Thanks for the suggestion!

{"protein_residues", ProteinLoaderColorScheme::protein_residues});

BRAYNS_MESSAGE_BEGIN(ProteinLoaderParameters)
BRAYNS_MESSAGE_ENTRY_DEFAULT(ProteinLoaderColorScheme, color_scheme,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can already specify a default value using Default(yourJsonValue) in the options after description, the advantage of doing so is that the default value will be specified in the JSON schema.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I didnt know. Ill remove the macro I added and use that. It would be something like: BRAYNS_MESSAGE_ENTRY(ProteinLoaderColorScheme, color_scheme, ProteinLoaderColorScheme::none, "Descriptrion") ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope something like:
BRAYNS_MESSAGE_ENTRY(Type, name, "description", Default("none"));

This is a JSON stuff so if you just want something to initialize the struct then you stuff is fine but if you need a JSON default value if this one is missing, then it is better to use the option as it will be marked in the schema.

@@ -0,0 +1,55 @@
#cmake_minimum_required(VERSION 3.15 FATAL_ERROR)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are all these commands commented ? In prevision of the removal of CMake/common ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of brayns core libraries are only compiled as part of the brayns project. It does not make sense to keep checking for version when we already do in the main CMakeListst.txt.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can remove the comments then ?

@@ -252,7 +245,7 @@ class MessageInfo
* will be serialized using JsonAdapter<TYPE>.
*
*/
#define BRAYNS_MESSAGE_PROPERTY(TYPE, NAME, ...) \
#define BRAYNS_MESSAGE_PROPERTY(TYPE, NAME, DEFAULT, ...) \
Copy link
Contributor

@Adrien4193 Adrien4193 Oct 29, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Default(json) value allows to set a default value that will be visible in the JSON schema so if the property is not found, it will make as if the provided JSON was extracted.

But if you just need to set a default value programatically in the struct without specifying it in the JSON schema, then I guess it is fine.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I didnt know it was possible already. Ill change it back.


namespace
{
inline std::vector<uint64_t> __parseIDRanges(const std::string& input)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why inline ?

Double underscores names are reserved for the compiler no ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didnt know double underscores where reserverd for the compiler. I know thats "kind of" a rule for python private vars, but I've seen this type of coding style in other softward. I personally use double underscore to denote anonymous private namespace functions.

I mark it inline because its a function used only within the cpp where is defined (usually just once or twice max), so I though I would avoid an extra jump without compiled code storage space overhead.


namespace
{
inline auto __getFIImageFormat(const std::string& format) noexcept
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inline ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mark it inline because its a function used only within the cpp where is defined (usually just once or twice max), so I though I would avoid an extra jump without compiled code storage space overhead.


namespace
{
inline std::unique_ptr<Simulation> __intantiateSimulation(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inline ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mark it inline because its a function used only within the cpp where is defined (usually just once or twice max), so I though I would avoid an extra jump without compiled code storage space overhead.


namespace
{
inline void __checkInput(const NeuronMorphologyLoaderParameters& input)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inline ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mark it inline because its a function used only within the cpp where is defined (usually just once or twice max), so I though I would avoid an extra jump without compiled code storage space overhead.

_fixedDefaults.add(
{PROP_POSTSYNAPTIC_NEURON_GID.getName(), std::string("")});
_fixedDefaults.add(PROP_SYNCHRONOUS_MODE);
inline auto selectNodes(const bbp::sonata::CircuitConfig& config,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inline ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mark it inline because its a function used only within the cpp where is defined (usually just once or twice max), so I though I would avoid an extra jump without compiled code storage space overhead.

{
namespace
{
inline auto __load(const brain::Synapses& src, const brain::GIDSet& gids,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inline ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mark it inline because its a function used only within the cpp where is defined (usually just once or twice max), so I though I would avoid an extra jump without compiled code storage space overhead.


namespace
{
inline auto __frameIndexToTimestamp(const uint32_t frame,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inline ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mark it inline because its a function used only within the cpp where is defined (usually just once or twice max), so I though I would avoid an extra jump without compiled code storage space overhead.

};
} // namespace

void SectionWelder::proccess(NeuronMorphology& morphology) const
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ill fix it. The type is also present in 3 other classes

constexpr char attribEtype[] = "etype";
constexpr char attribMorphology[] = "morphology";

inline std::vector<std::string> __getEnumValueList(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inline ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mark it inline because its a function used only within the cpp where is defined (usually just once or twice max), so I though I would avoid an extra jump without compiled code storage space overhead.

{
using Range = std::pair<uint64_t, uint64_t>;

inline auto __computeMapping(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inline ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mark it inline because its a function used only within the cpp where is defined (usually just once or twice max), so I though I would avoid an extra jump without compiled code storage space overhead.

{
BRAYNS_ADAPTER_BEGIN(ColoringInformation)
BRAYNS_ADAPTER_NAMED_ENTRY("variable", variable,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use BRAYNS_ADAPTER_ENTRY directly as the name is the same as the JSON-RPC one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, ill change it

BRAYNS_MESSAGE_ENTRY(
uint32_t, spp,
"Samples per pixels (The more, the better visual result and "
"the slower the"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang automatic string slicing doesn't put them together it seems ^^

Adrien4193
Adrien4193 previously approved these changes Oct 29, 2021
Copy link
Contributor

@Adrien4193 Adrien4193 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left some minor comments but nothing blocking, if you want to merge like that it is OK for me.

- Using already in place default values for json messages
- Fixed loader parsing empty parameters (Thanks Adrien)
- Removed custom added BRAYNS_MESSAGE_ENTRY_DEFAULT
- Removed unused comments in braynsJson/CMakeLists.txt
- Removed inline specifier from functions
- Removed double underscores __ from functions
- Use JsonSchemaValidator::validate for a better error messaging when failing to parse loader parameters
@NadirRoGue
Copy link
Contributor Author

I addressed some of the review comments in the last commit.
Thanks for the review and the help!

@NadirRoGue
Copy link
Contributor Author

retest this please

@NadirRoGue
Copy link
Contributor Author

retest this please

1 similar comment
@NadirRoGue
Copy link
Contributor Author

retest this please

Will avoid compiler warning/error of ambiguous call caused by implicit construction of JsonValue (Poco::Dynamic::Var)
@NadirRoGue
Copy link
Contributor Author

retest this please

- Scene is not a parameter needed at loader construction time, is passed as argument when import is done
- Adjusted required and default parameter values for CircuitExplorer loaders
- Removed unused and inimplemented method of LoaderRegistry
@NadirRoGue NadirRoGue force-pushed the circuitexplorer_refactor branch from 8902a5e to 24a666a Compare November 1, 2021 14:58
@NadirRoGue NadirRoGue merged commit 3c517e7 into develop Nov 2, 2021
@NadirRoGue NadirRoGue deleted the circuitexplorer_refactor branch November 2, 2021 08:00
NadirRoGue added a commit that referenced this pull request Dec 14, 2021
* Core updates:
- Extracted Json functionality from braynsNetwork into a separate library
- Extracted common/utils functionality from braynsCommon into a separate library
- Updates loaders to use compile time parameters.
- Scene is not a parameter needed at loaders construction time, is passed as argument when import is done
- Removed unused and unimplemented method of LoaderRegistry
- Updates copyright notice year
- Fixes simulation colors on snapshot
* CircuitExplorer updates:
- Rewritten frame export functionality
- Removed unused loaders and rewritten remaining ones
- Added full SONATA multi-population support
- Making MaterialRangeProxy::commit() const to avoid ambigous call to deserialize()
- Removes unnecessary cmake directives
NadirRoGue added a commit that referenced this pull request Dec 15, 2021
* Bumped Pillow and websockets version. (#922)

* Code cleanup (#923)

* Brayns 278 add mock requests in python tests (#924)

* Brayns 285 fix logic issue in quanta jpeg stream (#925)

* Brayns 286 fix python image method (#928)

* Brayns 287 fix python entrypoint methods with one of schema (#929)

* Loaders & CircuitExplorer refactoring (#927)

* Fixed some typo's (#930)

* Update AUTHORS.txt (#931)

* Brayns 258 create a proper logging system for brayns (#932)

* Frame export improvement and static global objects removal: (#933)

* Removes CMake/common dependency from build system (#934)

* Removed VRPN plugin and deps. (#935)

* Brayns 295 rename brayns json macros to a more appropriate name (#936)

* Fixes segfault due to global const std::strings (#939)

* Map and unmap framebuffer added. (#940)

* Fix entry points variable naming (#941)

* Brayns 300 replace free image (#942)

* Brayns 308 Code restructure (#943)

* Brayns 315 2.0.0 release preparation (#944)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants